本文是【Knockout.js 学习体验之旅】系列文章的第3篇,所有demo均基于目前knockout.js的最新版本(3.4.0)。小茄才识有限,文中若有不当之处,还望大家指出。

目录:

【Knockout.js 学习体验之旅】(1)ko初体验

【Knockout.js 学习体验之旅】(2)花式捆绑

【Knockout.js 学习体验之旅】(3)模板绑定

模板引擎

页面是由数据和HTML组件构成的,如何将数据嵌入到HTML组件里面呢?一个比较好的选择是使用模板技术。

回顾下第一篇(【Knockoutjs 学习体验之旅】(1)ko初体验)开头的总价计算:

 <!--HTML Code-->
<div class="counter">
Price: <input type="text" data-bind="{value: price, valueUpdate: 'afterkeydown'}" placeholder="请输入单价" /><br />
Account: <input type="text" data-bind="textInput: account" placeholder="请输入个数" /><br />
sum: <span data-bind="text: sum"></span>
</div>

这就是一个简单的组件,他有自己的内部结构,有自己的事件处理机制。假如我需要使用很多个这样的组件,那肯定不会是将上面的HTML代码复制 n 遍插入到不同的地方吧,况且单纯复制还不行,还要将变量区分开呢!如果是在一个列表里面,那可以用 foreach 来做,如果是要用在不同的容器内,那就要使用模板引擎技术了。

模板技术并不是什么高深的东西,有基于字符串拼接技术的,有基于 DOM 节点的,还有混合着的。更具体的介绍可以看一看这个轮子哥的文章 http://www.tuicool.com/articles/qMJ77r,楼主就不班门弄斧了。knockout.js 也是基于DOM节点的模板技术,编译之后 view 与 data 还是保持绑定关系,可以简单方便地更新数据到 view 层。另外你也可以将 knockout.js 链接到第三方的模板引擎,如 jquery.tmplUnderscore等模板引擎

下面简单讲讲ko中模板绑定的使用,第三方的集成引用不在本文讨论范围内。

knockout.js 的模板绑定

先看一个例子:

 <h2>Participants</h2> Here are the participants:
<div data-bind="template: { name: 'person-template', data: buyer }"></div>
<div data-bind="template: { name: 'person-template', data: seller }"></div> <!--模板-->
<script type="text/html" id="person-template">
<h3 data-bind="text: name"></h3>
<p>Credits: <span data-bind="text: credits"></span></p>
</script> <script type="text/javascript">
function MyViewModel() {
this.buyer = { name: 'Franklin', credits: 250 };
this.seller = { name: 'Mario', credits: 5800 };
}
ko.applyBindings(new MyViewModel());
</script>

<script type="text/html" id="person-template">这个script脚本标签定义了一个 id 为"person-template"的模板,ko就是通过这个 id 来寻找相应的模板。注意这个脚本的 type 是"text/html",所以才能跟正常的脚本区分开。ko不会自动绑定在这种脚本内的代码,只有在这个模板被使用的时候才会去绑定。

使用方法:HTML元素中使用 data-bind 绑定用到的模板,在 js 中定义相应的数据并应用该绑定。可以看到上面的"person-template"被引用了两次,一次使用的是buyer的数据,另一次使用了seller数据。下面简单说说模板绑定中用到的参数:

  • name — 指定你要渲染的模板片段,跟模板脚本中的 id 相对应。
  • nodes — 直接传递一个DOM节点数组作为模板使用。传递的DOM节点数列应该是不被监控的,因为渲染过程中会对这个节点数列进行复制赋值等操作。而且如果这个节点数组有父级节点的话也会被移除。当我们传递了一个非空的name值时,nodes选项会被忽略,所以很少会用到这个属性。
  • data — 用来作为渲染数据的对象。如果你忽略整个参数,KO将查找foreach参数,或者是应用整个view model对象。
  • if — 与上一篇中的 if 作用类似,只有当 if 后的表达式为真时才会渲染模板,用于防止一个空可观察对象在模板被填充之前被绑定。
  • foreach — 按照“foreach”模式渲染模板。
  • as — 结合foreach使用的时候,指定每项渲染数据的别名,主要是用于定义数据范围方便在嵌套绑定里面使用。
  • afterRender, afterAdd, or beforeRemove — 渲染时的回调函数。

下面简单简单介绍一下几种用法。

一些例子

  • 使用 foreach 渲染 ViewModel中的所有数据
 <h2>Participants</h2>
Here are the participants:
<div data-bind="template: { name: 'person-template', foreach: people }"></div> <script type="text/html" id="person-template">
<h3 data-bind="text: name"></h3>
<p>Credits: <span data-bind="text: credits"></span></p>
</script> function MyViewModel() {
this.people = [
{ name: 'Franklin', credits: 250 },
{ name: 'Mario', credits: 5800 }
]
}
ko.applyBindings(new MyViewModel());

这个例子跟上面的例子效果是一样的,使用 foreach 会将所有数据都渲染到模板中。区别就在于HTML的层级,使用data指定的时候,每一份数据渲染到对应的容器中;使用foreach的时候所有数据都被绑定到了一个容器内。上一篇中也介绍了foreach的用法,用不用模板都能得到一样的效果。回忆一下foreach的写法:

 <div data-bind="foreach: people">
<h3 data-bind="text: name"></h3>
<p>Credits: <span data-bind="text: credits"></span></p>
</div>
  • as 在嵌套绑定中的使用
 <ul data-bind="template: { name: 'seasonTemplate', foreach: seasons, as: 'season' }"></ul>

 <script type="text/html" id="seasonTemplate">
<li>
<strong data-bind="text: name"></strong>
<ul data-bind="template: { name: 'monthTemplate', foreach: months, as: 'month' }"></ul>
</li>
</script> <script type="text/html" id="monthTemplate">
<li>
<span data-bind="text: month"></span>
is in
<span data-bind="text: season.name"></span>
</li>
</script> <script>
var viewModel = {
seasons: ko.observableArray([
{ name: 'Spring', months: [ 'March', 'April', 'May' ] },
{ name: 'Summer', months: [ 'June', 'July', 'August' ] },
{ name: 'Autumn', months: [ 'September', 'October', 'November' ] },
{ name: 'Winter', months: [ 'December', 'January', 'February' ] }
])
};
ko.applyBindings(viewModel);
</script>

上面这种多层的绑定中,要在下级绑定层次中要引用上层的话,就可以使用 as 定义的别名了。当然层次简单的时候,用$parent也是可以的,用 as 会更加清晰,不会纠结在层次关系中。

注意:as 后接的别名应该用引号引起来,因为这里我们是命名一个变量,而不是读取一个已经存在的变量。

  • 动态决定使用哪个模板
 <ul data-bind='template: { name: displayMode, foreach: employees }'> </ul>
<script id="active" type='text/html'>
<li><span data-bind='text: name'></span>uses the "active" template!</li>
</script>
<script id="inactive" type='text/html'>
<li><span data-bind='text: name'></span>uses the "inactive" template!</li>
</script> <script>
var viewModel = {
employees: ko.observableArray([{
name: "Kari",
active: ko.observable(true)
}, {
name: "Brynn",
active: ko.observable(false)
}, {
name: "Nora",
active: ko.observable(false)
}]),
displayMode: function(employee) {
// Initially "Kari" uses the "active" template, while the others use "inactive"
return employee.active() ? "active" : "inactive";
}
};
// ... then later ...
viewModel.employees()[1].active(true);
// Now "Brynn" is also rendered using the "active" template.
ko.applyBindings(viewModel);
</script>

上面这个例子有 active 和 inactive 两个模板,ul 元素的 name 没有直接指定模板 id ,而是通过一个函数返回模板 id,达到了选择不同模板的目的。

吐槽一下:官方的文档相当省,模板脚本都省掉了。。。博客园的汤姆大叔,居然也就那样搬下来了,纯翻译的让人无语。

Mapping插件

模板技术可以简单地将数据和表现分离,采用前端渲染技术时,后台只要将模型数据发给客户端即可,前端将获取到的数据渲染输出。目前为止都是手动将获取到的数据写入 ViewModel 中,而 Mapping 插件就是帮你自动完成创建 ViewModel 的好工具。对比一下手动创建和使用 Mapping 插件两种方式:

手动创建:

 // setup
var viewModel = {
serverTime: ko.observable(),
numUsers: ko.observable()
}
// update:
var data = getDataUsingAjax(); // your method to get data from server
viewModel.serverTime(data.serverTime);
viewModel.numUsers(data.numUsers);

Mapping插件

 var data = getDataUsingAjax();  // your method to get data from server
var viewModel = ko.mapping.fromJS(data);
ko.mapping.fromJS(data, viewModel);

假如从服务器中获取的数据比较多的话,使用Mapping的确可以减少很多代码量。使用Mapping之后,data对象的所有属性都被设置成可观察对象,所有数组都被设置成可观察对象数组,数组中的顺序依然被保存。改变data对象的属性或者增减数组项目就可以引起绑定更新事件。Mapping插件还有很多高级用法,不过除非非Mapping插件不可的情况,没必要对一个插件投入太多精力去学习,搞太多还不如手写算了。

总结

本篇主要简单介绍了knockoutjs中模板技术的使用,感觉 ko 中用到的技术应该也差不多就这些了,自定义绑定和组件绑定相关的内容暂时没有用到就不去深究了。组件的写法有很多种,不一定要用 ko 的组件封装规则,各有所好。 下一篇将会用一个综合实例来介绍 ko 的各种绑定用法,敬请期待~~

码字不易,随手点赞哈~~~

参考资料:

  1. 官方教程: http://knockoutjs.com/documentation/introduction.html
  2. 汤姆大叔教程(官方教程翻译,版本太旧,信息缺失明显): http://www.cnblogs.com/TomXu/archive/2011/11/21/2257154.html
  3. 一个对前端模板技术的全面总结: http://www.tuicool.com/articles/qMJ77r

文字较多,惯例凑图!

(图片来源:网络)

原创文章,转载请注明出处!本文链接:http://www.cnblogs.com/qieguo/p/5579888.html  

【Knockout.js 学习体验之旅】(3)模板绑定的更多相关文章

  1. 【Knockout.js 学习体验之旅】(2)花式捆绑

    本文是[Knockout.js 学习体验之旅]系列文章的第2篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...

  2. 【Knockout.js 学习体验之旅】(1)ko初体验

    前言 什么,你现在还在看knockout.js?这货都已经落后主流一千年了!赶紧去学Angular.React啊,再不赶紧的话,他们也要变out了哦.身旁的90后小伙伴,嘴里还塞着山东的狗不理大蒜包, ...

  3. Knockout.js初体验

    前不久在网上看到一个轻量级MVVM js类库叫Knockout.js,觉得很好奇,搜了一下Knockout.js相关资料,也初体验了一下,顿时感觉这个类库的设计很有意思.接下来就搞清楚什么是Knock ...

  4. Knockout.Js学习目录

    1.Knockout.Js(简介) 2.Knockout.Js(监控属性Observables) 3.Knockout.Js(属性绑定) 4.Knockout.Js(事件绑定) 5.Knockout. ...

  5. 关于 knockout js 学习中的疑问 (1)

    最近刚刚学习knockout中遇到如下问题: 1.在给viewModel定义一个方法时,有时后面跟 的this,有的时候没有 如下所示: this.fullName = ko.computed(fun ...

  6. Node.js学习(2)-使用模板引擎art-template

    node 安装cnpm i -S art-template 加载require('art-template') template.render接收的是字符串

  7. Vue.js学习 Item9 – 表单控件绑定

    基础用法 可以用 v-model 指令在表单控件元素上创建双向数据绑定.根据控件类型它自动选取正确的方法更新元素.尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据,以及特别处理一些 ...

  8. Vue.js学习笔记--3.表单输入绑定

    整理自官网教程 -- https://cn.vuejs.org/ 利用v-model可以实现表单元素的value与后台数据的双向绑定,具体用法如下: <!--文本--> <input ...

  9. Knockout学习之模板绑定器

    模板绑定器 如今页面结构越来越复杂,仅仅依靠foreach已经不足以我们的使用,这个时候我们就需要模板的存在,模板的优点自然很多,首先会让页面整洁,同时修改起来也可以方面的定位,最重要的是ko可以条件 ...

随机推荐

  1. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

  2. 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户

    阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...

  3. System.FormatException: GUID 应包含带 4 个短划线的 32 位数(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。

    在NHibernate数据库查询中出现了这个错误,由于是数据库是mysql的,当定义的字段为char(36)的时候就会出现这个错误. [解决方法] 将char(36) 改成varchar(40)就行了 ...

  4. 当web.config文件放置在共享目录下(UNC),启动IIS会提示有错误信息500.19,伴随有错误代码0x80070003和错误代码0x80070005的解决办法

    最近遇到一个很有意思的使用环境,操作人员将所有的网站应用内容投放到共享存储里面,并且使用微软的SMB协议将其以CIFS的方式共享出来,使用Windows Server 2008 R2的IIS将其连接起 ...

  5. mount报错: you must specify the filesystem type

    在linux mount /dev/vdb 到 /home 分区时报错: # mount /dev/vdb /homemount: you must specify the filesystem ty ...

  6. 听H3絮叨:何以让天下没有难用的流程

    最近朋友圈.网站新闻铺天盖地是"让天下没有难用的流程",有人就要问了,H3 BPM何德何能,为BPM站台,让天下没有难用的流程? 这是一个关于"办公室空想"的故 ...

  7. 解决mysql插入数据时出现Incorrect string value: '\xF0\x9F...' for column 'name' at row 1的异常

    这个问题,原因是UTF-8编码有可能是两个.三个.四个字节.Emoji表情或者某些特殊字符是4个字节,而MySQL的utf8编码最多3个字节,所以数据插不进去. 我的解决方案是这样的 1.在mysql ...

  8. hbase集群安装与部署

    1.相关环境 centos7 hadoop2.6.5 zookeeper3.4.9 jdk1.8 hbase1.2.4 本篇文章仅涉及hbase集群的搭建,关于hadoop与zookeeper的相关部 ...

  9. 【教程】SQLite数据库修复

    SQLite 大家都知道,就不多说了. 有时候数据量大了,或者存储过程中出现异常,数据库就可能会出问题. 这是以前公司产品出现过的问题,导致软件都打不开了,我花了不少时间才解决的,趁现在有空贡献出来. ...

  10. windows下的命令行工具babun

    什么是babun babun是windows上的一个第三方shell,在这个shell上面你可以使用几乎所有linux,unix上面的命令,他几乎可以取代windows的shell.用官方的题目说就是 ...