zoukankan      html  css  js  c++  java
  • 【Knockout.js 学习体验之旅】(3)模板绑定

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

    目录:

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

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

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

    模板引擎

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

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

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

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

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

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

    knockout.js 的模板绑定

    先看一个例子:

      1 <h2>Participants</h2> Here are the participants:
      2 <div data-bind="template: { name: 'person-template', data: buyer }"></div>
      3 <div data-bind="template: { name: 'person-template', data: seller }"></div>
      4 
      5 <!--模板-->
      6 <script type="text/html" id="person-template">
      7     <h3 data-bind="text: name"></h3>
      8     <p>Credits: <span data-bind="text: credits"></span></p>
      9 </script>
     10 
     11 <script type="text/javascript">
     12     function MyViewModel() {
     13         this.buyer = { name: 'Franklin', credits: 250 };
     14         this.seller = { name: 'Mario', credits: 5800 };
     15     }
     16     ko.applyBindings(new MyViewModel());
     17 </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中的所有数据
      1 <h2>Participants</h2>
      2 Here are the participants:
      3 <div data-bind="template: { name: 'person-template', foreach: people }"></div>
      4 
      5 <script type="text/html" id="person-template">
      6     <h3 data-bind="text: name"></h3>
      7     <p>Credits: <span data-bind="text: credits"></span></p>
      8 </script>
      9 
     10  function MyViewModel() {
     11      this.people = [
     12          { name: 'Franklin', credits: 250 },
     13          { name: 'Mario', credits: 5800 }
     14      ]
     15  }
     16  ko.applyBindings(new MyViewModel());

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

      1 <div data-bind="foreach: people">
      2     <h3 data-bind="text: name"></h3>
      3     <p>Credits: <span data-bind="text: credits"></span></p>
      4 </div>
    • as 在嵌套绑定中的使用
      1 <ul data-bind="template: { name: 'seasonTemplate', foreach: seasons, as: 'season' }"></ul>
      2 
      3 <script type="text/html" id="seasonTemplate">
      4     <li>
      5         <strong data-bind="text: name"></strong>
      6         <ul data-bind="template: { name: 'monthTemplate', foreach: months, as: 'month' }"></ul>
      7     </li>
      8 </script>
      9 
     10 <script type="text/html" id="monthTemplate">
     11     <li>
     12         <span data-bind="text: month"></span>
     13         is in
     14         <span data-bind="text: season.name"></span>
     15     </li>
     16 </script>
     17 
     18 <script>
     19     var viewModel = {
     20         seasons: ko.observableArray([
     21             { name: 'Spring', months: [ 'March', 'April', 'May' ] },
     22             { name: 'Summer', months: [ 'June', 'July', 'August' ] },
     23             { name: 'Autumn', months: [ 'September', 'October', 'November' ] },
     24             { name: 'Winter', months: [ 'December', 'January', 'February' ] }
     25         ])
     26     };
     27     ko.applyBindings(viewModel);
     28 </script>

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

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

    • 动态决定使用哪个模板
      1 <ul data-bind='template: { name: displayMode, foreach: employees }'> </ul>
      2 <script id="active" type='text/html'>
      3     <li><span data-bind='text: name'></span>uses the "active" template!</li>
      4 </script>
      5 <script id="inactive" type='text/html'>
      6     <li><span data-bind='text: name'></span>uses the "inactive" template!</li>
      7 </script>
      8 
      9 <script>
     10     var viewModel = {
     11         employees: ko.observableArray([{
     12             name: "Kari",
     13             active: ko.observable(true)
     14         }, {
     15             name: "Brynn",
     16             active: ko.observable(false)
     17         }, {
     18             name: "Nora",
     19             active: ko.observable(false)
     20         }]),
     21         displayMode: function(employee) {
     22             // Initially "Kari" uses the "active" template, while the others use "inactive"
     23             return employee.active() ? "active" : "inactive";
     24         }
     25     };
     26     // ... then later ...
     27     viewModel.employees()[1].active(true);
     28     // Now "Brynn" is also rendered using the "active" template.
     29     ko.applyBindings(viewModel);
     30 </script>

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

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

    Mapping插件

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

    手动创建:

      1 // setup
      2 var viewModel = {
      3     serverTime: ko.observable(),
      4     numUsers: ko.observable()
      5 }
      6 // update:
      7 var data = getDataUsingAjax();  // your method to get data from server
      8 viewModel.serverTime(data.serverTime);
      9 viewModel.numUsers(data.numUsers);

    Mapping插件

      1 var data = getDataUsingAjax();  // your method to get data from server
      2 var viewModel = ko.mapping.fromJS(data);
      3 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

    文字较多,惯例凑图!

    tibet-lake

    (图片来源:网络)

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

  • 相关阅读:
    php实现简单的流程管理
    【百度地图API】如何制作多途经点的线路导航——驾车篇
    利用MFC实现浏览器的定制与扩展(JavaScript与C++交互)
    c++与js脚本交互,C++调用JS函数/JS调用C++函数
    VC/MFC中通过CWebPage类调用javascript函数(给js函数传参,并取得返回值)
    Android中半透明Activity效果另法
    mac java环境
    在Mac osx使用ADT Bundle踩过的坑
    Android自动检测版本及自动升级
    C++编译遇到参数错误(cannot convert parameter * from 'const char [**]' to 'LPCWSTR')
  • 原文地址:https://www.cnblogs.com/qieguo/p/5579888.html
Copyright © 2011-2022 走看看