KnockoutJs 进阶学习

时间 2014-11-22 20:59:13 CSDN博客 原文  http://blog.csdn.net/huyute/article/details/41386279

Q: KnockOut的双向绑定是如何工作的呢?

A: 原理上还是挺简单的:

  1. 声明Observable的时候记住当前的值, var personName =     ko.observable("");
  2. 在HTML里declarative     binding时,即data-binding="text: personName",会注册一个subscriber 到personName
  3. 当personName的值发生变化时,会通知所有的subscriber,触发对应的行为
  4. 重新记录这个新的值,循环#c步骤。

顺便提下,如果想让personName改变后还是原值的时候也触发subscriber,可以用extender

myViewModel.personName.extend({ notify: 'always' });

Q: 为什么ViewModel的官方规范里面需要var self= this;

A: 防止在事件触发的时候ViewModel的this和事件自己的this混淆

Q: 区别: subscribe vs computed vs extend

如果需要处理由值变化而引发另一个操作的场景,可以有几种方式:

  1. Subscribe在单值变化的时候使用;
  2. Computed在多个值变化的时候使用;
  3. Extend则一般定义了通用方法,可以让多个observable公用同一个extend方法,类似于C#里面的filter.

具体用法如下:

  1. Subscribe, 该方法有3个参数:

    1. callback是由值变化后触发的callback函数
    2. Target:可选项,callback的this值
    3. event可以定义callback 函数触发的事件,比如: beforeChange,默认是用 change
myViewModel.personName.subscribe(function(newValue) {alert("Theperson's new name is " + newValue);
});

PS: KO的官方文档里解释是,KO在HTML里的声明绑定(Decliaritivebinding),就是使用subscribe的机制来实现的。

既然可以显示声明subscribe,也就可以把它dispose掉

var subscription =myViewModel.personName.subscribe(function(newValue) { /* do stuff */ });// ...then later...
subscription.dispose(); // I no longer want notifications
  1. Computed:

如果在computed里面的KO对象的值有变更,都会触发computed函数执行:

function AppViewModel() {  this.firstName = ko.observable('Bob');
  this.lastName = ko.observable('Smith');
}function AppViewModel() {  // ... leave firstName and lastNameunchanged ...  this.fullName = ko.computed(function() {
    return this.firstName() + " " +this.lastName();
  }, this);
}

这里,传递this是 为了在computed里读取fistName和lastName.

如果要在改变fullName的时候反向改变firstName和LastName,可以定义里面的write callback, 我使用过的一个场景是一个checkbox控制所有其他Itemcheckbox的 select和unselect.

function MyViewModel() {  this.firstName =ko.observable('Planet');
  this.lastName = ko.observable('Earth');
  this.fullName = ko.pureComputed({
    read:function () {      return this.firstName() + " " +this.lastName();
    },
    write:function (value) {      var lastSpacePos = value.lastIndexOf(" ");
      if (lastSpacePos > 0) { // Ignore values with no space character
        this.firstName(value.substring(0,lastSpacePos)); // Update "firstName"
        this.lastName(value.substring(lastSpacePos+ 1)); // Update "lastName"
      }
    },
    owner: this
  });
}
  1. Extender:

Target参数传递被extend的对象,option传递外部的值

ko.extenders.logChange = function(target, option) {target.subscribe(function(newValue) {console.log(option+ ": " + newValue);});return target;
};
this.firstName =ko.observable("Bob").extend({logChange: "first name"});

区别:Computed VS Pure Computed

Pure Computed只有当有其他subscriber的时候才会有这个对象,所对应的DOM对象 不激活的时候不存在,这样可以防止内存泄露,在Component等场景下不用担心dispose的问题。

如果computed里面的对象不会有其他写的操作,优先使用pure computed

"text" binding 注意事项:

Text binding非常常用,使用也非常简单,但是要注意一些场景:

Today's message is: <span data-bind="text:myMessage"></span> <script type="text/javascript"> var viewModel = { myMessage:ko.observable() // Initially blank }; viewModel.myMessage("Hello,world!"); // Text appears
</script>
  1. 如果text是非number或string, 它的值会转换成ToString()的形式显示,比如显示成Object
  2. text会过滤掉所有HTML元素防止Javascript注入,如果要保护HTML元素,使用HTML绑定

关于绑定上下文:

首先理解下上下文Context和上下文ViewModel的对象,以$parentContext和$parent为例:

var initialData = [  {      firstName: "Danny",lastName: "LaRusso", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C2", phones: [        { type: "Mobile",number: "(555) 121-2121", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C1" },        { type: "Home", number:"(555) 123-4567", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C5" }]  },  {
      firstName: "Sensei",lastName: "Miyagi", id:"C6A2D391-6B68-42EA-9EE2-3E2575614334", phones: [
        { type: "Mobile",number: "(555) 444-2222", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C20" },
        { type: "Home", number:"(555) 999-1212", id:"C6A2D391-6B67-42EA-9EE2-3E25756143C2" }]
  }];

假设当前的上下文是在Phones, 如果要访问父级的firstName, lastName对象,可以用$parentContext先获取父级的上下文,然后再取出对象<spandata-bind="text: $parentContext.contact.firstName"></span>

也可以用$parent取得父级上下文的object: {  firstName:"Danny", lastName: "LaRusso", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C2"},

然后直接取得firstName的值 <span data-bind="text:$parent.firstName"></span>

KO定义很一些上下文绑定对象,可以方便的找到当前和不同层别的上下文。

  1. $parent,  $parents and $root

$parent可以找到上级的对象, $parents[0], $parents[1].$parents[$parents.length -1]则一级一级往上找。

<h1 data-bind="text:name"></h1><div data-bind="with:manager"><!-- Now we're inside a nested binding context --><span data-bind="text:name"></span> is themanager of <span data-bind="text: $parent.name"></span>
</div>

如果当前的上下文是root, $parent和$parents都会是undefined, $parents[$parents.length-1]也相当于$root.

  1. $data, 存储当前上下文的ViewModel对象,同样, 在root上下文,$data相当于$root
<table>
  <thead>
    <tr><th>Firstname</th><th>Last name</th></tr>  </thead>
  <tbody data-bind="foreach:people">
    <tr>
      <td data-bind="text: $data.firstName"></td>
      <td data-bind="text: lastName"></td>
    </tr>
  </tbody>
</table><script type="text/javascript">
  ko.applyBindings({
    people: [
      { firstName: 'Bert', lastName: 'Bertington' },
      { firstName: 'Charles', lastName: 'Charlesforth' },
      { firstName: 'Denise', lastName: 'Dentiste' }
    ]
  });
</script>
  1. $context and $parentContext

$context是当前的上下文,$parentContext对应的是父级的上下文

  1. $element

当前绑定的DOM对象

<div id="item1"data-bind="text:$element.id"></div>
  1. Foreach会改变当前的上下文,和 with 绑定可以主动的改变当前的上下文
<h1 data-bind="text: city"> </h1> <p data-bind="with: coords">   Latitude: <span data-bind="text:latitude"> </span>,  Longitude: <spandata-bind="text: longitude"> </span></p> <script type="text/javascript">   ko.applyBindings({     city:"London",     coords: {       latitude: 51.5001524,       longitude:-0.1262362     }   }); </script>

非常好用的数据转化observable插件:Ko.mapping

这是一个插件,能复杂对象的数据和子层数据转化成Observable, 没有在KO自带的js里,需要额外 下载,用法:

self.changeRequest = ko.mapping.fromJS(data); //data里面的所有数据都会变成observable

如果要更新整个对象,通过直接的赋值self.changeRequest没有作用,可以通过以下方法:

ko.mapping.fromJS(result,instance.changeRequestViewModel.changeRequest);

区别 If binding vs visible binding vs with

if 绑定会根据条件判断是否生成对应的DOM对象,而Visiable只是通过css显示和隐藏DOM对象,两者的使用场景还是有所差别的。比如,根据用户当前的权限判断时候可以显示某个操作时,最好还是使用if,可以防止别人通过修改HTML属性看到这个DOM对象。

with除了改变上下文的级别,还有另一个特性,当内部的元素不存在时,不会出现找不到元素的绑定错误。

Click 绑定注意事项:

Click 事件会默认传递当前上下的 ViewModel值和触发的事件对象给函数, 如果要改变函数,可以有两个办法:

<button data-bind="click: function(data, event) {myFunction('param1', 'param2', data, event) }">  Click me </button><button data-bind="click: myFunction.bind($data,'param1', 'param2')">  Click me </button>

一般情况下,声明了click绑定之后,就不会触发其他的点击事件了,比如a标签的href,如果还想继续触发,在click的函数里返回true

Form相关的绑定注意事项:

  1. Checkbox 和radio 按钮请使用checked 绑定(不用value), 只需声明个数组 this.checkedList=     ko.observableArray(); 然后在HTML绑定时指定value和checked就能实现多选,不需要很复杂的代码:     databind="value: Id, checked: checkedList", checkedList取到的就是选中的Id列表。
  2. Input标签需要使用textInput 绑定而不是value绑定, 区别在于,textInput在值改变的时候就能触发, value要等到keydown才行。

参考: http://knockoutjs.com/documentation/introduction.html

Knockout subscribe,computed,extend相关推荐

  1. Knockout.js----使用计算属性(Computed Observable)

    计算属性 Computed Observable 如果你已经有了一个监控属性firstName和lastName,如果你想显示全名该怎么做呢?这个时候你就可以通过计算属性来实现,这个方法依赖于一个或多 ...

  2. knockout 学习笔记

    1.激活knockout ko.applayBindings() 第一个参数是激活ko时用于声明绑定的View Model的对象 (myViewModel= {personName: 'Bob',pe ...

  3. 【Knockout】二、监控属性Observables

    MVVM和viewModel Knockout是建立在以下三大核心功能之上的: 监控属性和依赖跟踪(Observables and dependency tracking) 声明式绑定(Declara ...

  4. Knockout中文开发指南(完整版API中文文档) 目录索引

    推荐阅读:https://www.cnblogs.com/smallprogram/p/5976954.html http://www.cnblogs.com/xqin/tag/easyui/ 一.下 ...

  5. Knockout.js 学习 (六)-- 监控属性数组 applyBinding Observables

    如果你想发现并响应一个对象的改变,就应该用监控属性(observables).如果你想发现并响应一个集合的变化,就该用监控属性数组(observableArray).监控属性数组在 显示或编辑多个值 ...

  6. Knockout v3.4.0 中文版教程-9-计算监控-API参考

    5.参考 下面的内容描述了如何构建和使用计算监控. 1. 构建一个计算监控 可以用如下的形式构建一个计算监控: ko.computed( evaluator [, targetObject, opti ...

  7. Knockout中ViewModel与Model的互转

    在我们平常的开发当中使用频率最多的就是CRUD(添加.更新.删除.查询). 而"添加"和"编辑"操作又是整个数据源的入口,在整个CRUD中占有非常重要的地位.常 ...

  8. knockout入门(二)

    knockout入门(二) knockout计算属性(Computed Observables) 定义"this" Pure computed 观察属性 计算属性对象始终通知用户 ...

  9. 了解KnockOut.js

    Knockout是微软出品,是MVVM模型领域内的先驱,使用函数偷龙转凤,最短编辑长度算法实现DOM的同步,兼容IE6. Knockout是一个JS的MVVM模式的实现,Knockout是建立在3个核 ...

最新文章

  1. c语言调用shell脚本或命令
  2. 递归二分法php,PHP基于二分法实现数组查找功能示例【循环与递归算法】
  3. VS2013建立C++ dll库文件
  4. FPGA与MCU,DSP(如C6000,C5000等)等设计思想的异同
  5. .NET Core微服务开发网篇-ocelot
  6. python提取英文单词 每行显示一个_使用python对文件中的单词进行提取
  7. Bailian2936 试剂配制【标记+逻辑】
  8. 读取jar包中的资源文件
  9. ROSt通信编程_服务编程
  10. 软件测试工具Winrunner TSL命令简介
  11. ADS软件仿真的问题
  12. Javaweb阶段学习
  13. win7无法打开计算机共享文件夹,win7共享文件夹怎么设置?win7共享文件夹无法访问...
  14. PatternLayout格式解读
  15. Android仿搜狗浏览器加载动画
  16. servlet登录验证并返回错误信息
  17. Android中基于心知天气API获取天气信息
  18. android图片压缩终极解决方案
  19. 流光溢彩 diy_您需要的只是流光溢彩
  20. TREC Real-Time Summarization Track

热门文章

  1. K8s日志组件-Loki是如何存储数据的?
  2. 11.FREQUENCY AND TEMPORAL CONVOLUTIONAL ATTENTION FORTEXT-INDEPENDENT SPEAKER RECOGNITION(2019.10)
  3. python+unity 做3d动画人物 python做骨骼识别 (一)
  4. Pycharm小技巧(一) 快速删除空白行
  5. 你期待的Photoshop 2022中哪个功能吸引了你?
  6. Android 超简单音乐播放器(三)根据歌曲名或者歌手搜索本地音乐(EditText监听)
  7. android mp3进度条和时间,AndroidStudio音乐播放器进度条和歌曲时间的操作
  8. 0008 实现MaxMaya共用一套GUI
  9. 基金评价专题1:绩效指标
  10. Spring基本使用(元素lookup-method使用)