knockoutJS学习笔记06:ko数组与模板绑定
前面已经介绍了基本的绑定和模板相关知识,接下来就看ko里的数组和模板绑定,数组和模板绑定应该是实际项目中用得比较多的,ko提供了很好的支持。
一、observaleArray
前面的监控属性都是单个对象,用的是ko.observable;有时候后台返回的是一个列表,也就是数组,这个时候就需要用监控数组了。监控数组与监控属性几乎一样,只不过它是一个数组对象,拥有数组的特点。例如:创建一个简单的监控数组:
1 | var arr = ko.observableArray(); |
也可以开始就进行初始化:
1 | arr = ko.observableArray([1,2,3]); |
普通数组获取长度就是 arr.length,而监控数组与监控属性一样,需要用方法,例如:arr().length。
二、监控数组常见方法
监控数组拥有普通数组的所有方法,用法也基本一样。
2.1 push 增加一个新元素
arr.push(4);
2.2 pop 删除一个元素,并返回这个元素
var v = arr.pop();
2.3 shift 在开始处删除一个元素,并返回这个元素
var v = arr.shift();
2.4 unshift 在开始处增加一个元素
arr.unshift(0);
2.5 reverse 反转数组
arr.reverse();
2.6 sort 数组排序
arr.sort();
可以看到,上面的方法和js里的数组方法一模一样,用法也是一样的。此外,ko还支持另外两个方法,remove 和 removeAll:
remove:移除指定元素或移除指定条件的元素。如:arr.remove(1); 或者 arr.remove(function(item){return item > 1;});
removeAll:移除指定的元素集或移除所有元素。如:arr.removeAll([1,2]); 或者 arr.removeAll();
上面数组的内容只是简单的数据类型,实际也可以复杂的类型。需要注意的是,为了提高性能,监控数组只监控数组对象,而不监控数组元素对象的属性。也就是说,如果arr元素是对象,那么对arr进行的操作会反应到UI(反之也会);但对arr[0]对象内部的属性的操作,就不会反应到UI(反之也不会)。
二、foreach 绑定
既然是数组,自然就需要遍历输出了。foreach 绑定就是用来遍历集合的,如果集合是空的,会在页面上留下一个空的模板。
2.1 foreach指定要遍历的属性,内部的结构会自动循环绑定。例如:
1 2 3 | < div data-bind="foreach:list"> < p >姓名:< span data-bind="text:name"></ span >,年龄:< span data-bind="text:age"></ span ></ p > </ div > |
2.2 通过 as 关键字为遍历的属性定义别名,这样就可以通过别名对它进行访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <ul data-bind= "foreach:{data:data,as:'data'}" > <li> <p data-bind= "text:name" ></p> <ul data-bind= "foreach:{data:contains,as:'item'}" > <li> <p><span data-bind= "text:item.name" ></span>属于<span data-bind= "text:data.name" ></span></p> </li> </ul> </li> </ul> var data = [ {name: "水果" ,contains:[{name: "苹果" ,work: "苹果的作用" },{name: "香蕉" ,work: "香蕉的作用" }]}, {name: "蔬菜" ,contains:[{name: "青菜" ,work: "青菜的作用" },{name: "白菜" ,word: "白菜的作用" }]} ]; ko.applyBindings(data); |
这里要注意,as后面的名称必须加引号。在ko里,凡是作为名称的,都必须加引号,而如果作为对象或者属性的,就不需要。
三、ko 模板绑定
ko 的模板用template指定,template 可以直接指定模板名称,也支持更多选项。
3.1 直接指定模板名称
1 | < div data-bind="template:'tmpl'"></ div > |
3.2 templdate 支持更多的选项,让我们可以更灵活的控制整个渲染过程。
name(必选项) — 需要render的模板ID。
data(可选项) — 需要render到模板的数据。如果你忽略整个参数,KO将查找foreach参数,或者是应用整个view model对象。
foreach(可选项) — 指定KO按照“foreach”模式render模板。
afterAdd或beforeRemove(可选项) — 在foreach模式下使用callback函数。
templateOptions(可选项) — 在render模板的时候,传递额外数据以便使用。
1 2 3 4 | <div data-bind= "template:{name:'koPersonList',foreach:list}" ></div> <script type= "text/tmpl" id= "koPersonList" > <p>姓名:<span data-bind= "text:name" ></span>,年龄:<span data-bind= "text:age" ></span></p> </script> |
另外,template里的name 属性不只可以写死为一个模板名称,还可以是一个方法属性,由它来动态决定使用哪个模板。例如下面的例子,在遍历的时候,会根据名称来决定使用哪个模板。
1 2 3 4 5 6 7 | <div data-bind= "template:{name:display,foreach:list}" ></div> this .display = function (item){ if (item.name() === "tom1" ){ return "tmpl1" ; //使用模板1渲染 } return "tmpl2" ; //使用模板2渲染 } |
三、结合jqtmpl
集合类型通常要进行遍历渲染,之前我们已经写过模板引擎了,也介绍了jsRender,都支持循环遍历。ko 默认支持的jqtmpl模板。简单介绍一下jqtmpl,它的 tag 有:
${变量} : 输出变量值
${{html 变量}} :输入变量html
${{if condition}}...${{else condition}}...${{else}}...${{/if}} :if-else 判断
${{each(index,item) 集合}...${{/each}} :遍历
可以看出,jqtmpl和jsRender的结构是非常像。我们用template集合jqtmpl看两个例子。
例子1:
1 2 3 4 | <div data-bind= "template:'person'" ></div> <script type= "text/tmpl" id= "person" > <p>姓名:${name},年龄:${age}</p> </script><strong>: </strong> |
例子2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <div id= "" data-bind= "template:{name:'personList',foreach:list}" ></div> <script type= "text/tmpl" id= "personList" > <p>姓名:${name},年龄:${age}</p> </script> function Person(name,age){ this .name = name; this .age = age; } function ViewModel(){ this .list = [ new Person( "tom" ,18), new Person( "jack" ,20), new Person( "lucy" ,22)]; } ko.applyBindings( new ViewModel()); |
注意:和jqtmpl一起使用时,ko.js必须先引入,后再引入jqtmpl.js,否则会没有效果。
上面的例子就是把ko的输出方式,换成jqtmpl的输出方式,结果是一样的。那么使用<span data-bind="text:someObservableValue"></span> 与 ${someObservableValue} 有什么区别呢?
当模板内部使用data-bind属性的时候,KO是单独为这个绑定单独跟踪依赖项的。当model改变的时候,KO只会更新绑定的元素以及子元素而不需要重新render整个模板。所以如果你声明这样的代码是<span data-bind='text: someObservableValue'></span>,当 someObservableValue改变的时候,KO将只是简单地更新<span>元素的text值而不需要重新render整个模板。
不过,如果模板内部使用的observable值(例如${ someObservableValue }),如果这个observable值改变了,那KO将重新render整个模板(这往往不是我们想要的)。
这就是说,很多情况下<span data-bind='text: someObservableValue'></span>性能要比${ someObservableValue }要好,因为值改变的话不会影响临近元素的状态。不过${ someObservableValue }语法比较简洁,如果你的模板比较小的话,还是更合适的,不会带来大的性能问题。
五、用ko模板完成开篇的demo
开篇我们用了多种方式完成一个简单的demo,这样用ko来完成相同的功能。
html:
1 2 3 4 | < div id="main"> < div id="title">所有课程</ div > < ul id="course" data-bind="template:{name:'courseTmpl',foreach:courseList}"></ ul > </ div > |
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | < script type="text/tmpl" id="courseTmpl"> < li > < a data-bind="attr:{href:'Default.aspx?courseID='+CourseID}"> < div class="course-img"> < img data-bind="attr:{src:IconPath,alt:CourseName}"/> </ div > < div class="course-info"> < div class="names"> < span data-bind="text:CourseName"></ span > < span data-bind="text:TeacherName" class="fr"></ span > </ div > < div class="pros"> < span data-bind="text:CreatedDate"></ span > < span class="fr">< span data-bind="text:StudyNumber"></ span >人学习</ span > </ div > </ div > </ a > </ li > </ script > |
js:
1 2 3 4 5 6 7 8 9 | function CourseInfoVM(){ var self = this ; this .courseList = ko.observableArray(); } var courseInfoVM = new CourseInfoVM(); ko.applyBindings(courseInfoVM,document.getElementById( "course" )); window.Tester.callback( function (data){ courseInfoVM.courseList(data); }) |
六、总结
ko的模板绑定提供了很多的功能和支持,让我们对集合类型的处理更加方便,页面的结构更加清晰,脚本更加简洁。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构