Knockout2.x开发 第二章:监控属性(Observable) 与 依赖属性(Computed)
2013-03-08 16:46 阅读(187)

监控属性(Observables)

Knockout是在下面三个核心功能是建立起来的:

  1. 监控属性(Observables)和依赖跟踪(Dependency tracking)
  2. 声明式绑定(Declarative bindings)
  3. 模板(Templating)

这一节,你将学到3个功能中的第一个。 在这之前, 我们来解释一下MVVM模式和view model的概念。

MVVM and View Models

Model-View-View Model (MVVM) 是一种创建用户界面的设计模式。 描述的是如何将复杂的UI用户界面分成3个部分:

实例讲解

创建一个view model,只需要声明任意的JavaScript object。例如

var myViewModel = {
    personName: 'Bob',
    personAge: 123
};

你可以为view model创建一个声明式绑定的简单 view 。例如:下面的代码显示 personName 值:

The name is <span data-bind="text: personName"></span>

激活 Knockout

data-bind 属性尽快好用但它不是HTML的原生属性(它严格遵从HTML5语法, 虽然HTML4验证器提示有不可识别的属性但依然可用)。由于浏览器不识别它是什么意思,所以你需要激活Knockout 来让他起作用。

激活Knockout,需要添加如下的 <script> 代码块:

ko.applyBindings(myViewModel);

你可以将这个代码块放在HTML底部,或者放在jQuery的$函数或者ready 函数里,然后放在页面上面。否则knockout无法搜索到声明式绑定的dom元素。 最终生成结果就是如下的HTML代码:

The name is <span>Bob</span>

完整代码:
<body>
The name is <span data-bind="text: personName"></span>
</body>
</html>
<script type="text/javascript">
var myViewModel = {
    personName: 'Bob',
    personAge: 123
};
ko.applyBindings(myViewModel);
</script>

你可能奇怪 ko.applyBindings 使用的是什么样的参数,


Observables

现在已经知道如何创建一个简单的view model并且通过binding显示它的属性了。但是KO一个重要的功能是当你的view model改变的时候能自动更新你的界面。当你的view model部分改变的时候KO是如何知道的呢?答案是:你需要将你的model属性声明成 observables的, 因为它是非常特殊的JavaScript objects,能够通知订阅者它的改变以及自动探测到相关的依赖。

例如:将上述例子的view model改成如下代码:

var myViewModel = {
    personName: ko.observable('Bob'),
    personAge: ko.observable(123)
};

你根本不需要修改view – 所有的data-bind语法依然工作,不同的是他能监控到变化,当值改变时,view会自动更新。


监控属性(observables)的读和写

不是所有的浏览器都支持JavaScript的 getters and setters (比如IE),,所以为了兼容性,使用 ko.observable监控的对象都是真实的 functions函数。

监控属性(observables)的特征就是监控(observed),例如其它代码可以说我需要得到对象变化的通知,所以KO内部有很多内置的绑定语法。所以如果你的代码写成 data-bind="text: personName" , text 绑定注册到自身,一旦 personName 的值改变,它就能得到通知。

当然调用 myViewModel.personName('Mary') 改变name的值, text 绑定将自动更新这个新值到相应的DOM元素上。这就是如何将view model的改变传播到view上的。


通常情况下,你不用手工订阅,所以新手可以忽略此小节。
监控属性(Observables)的显式订阅

高级用户,如果你要注册自己的订阅到监控属性(observables),你可以调用它的 subscribe 函数。例如:

myViewModel.personName.subscribe(function(newValue) {
    alert("The person's new name is " + newValue);
});
这个 subscribe 函数在内部很多地方都用到的。你也可以终止自己的订阅:首先得到你的订阅,然后调用这个对象的 dispose 函数,例如:

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



依赖属性(Computed Observables)

在早期版本中叫做dependentObservable,也有人叫自动计算属性。它通常依赖于其他的Observable,通过计算得出自己的数据。当依赖项改变的时候,computed属性会接到通知,然后同步更新自身

如何使用

如果你已经有了监控属性(observable) for firstName 和 lastName,你想显示全称怎么办?这就需要用到 依赖属性(computed observables) 了 – 这些函数是一个或多个监控属性, 如果他们的依赖对象改变,他们会自动跟着改变。

例如,下面的view model,

function AppViewModel() {
    var self = this;
 
    self.firstName = ko.observable('Bob');
    self.lastName = ko.observable('Smith');  
}

…你可以添加一个依赖属性来返回姓名全称:

function AppViewModel() {
   // ... leave firstName and lastName unchanged ...
   
   self.fullName = ko.computed(function() {
        return self.firstName() + " " + self.lastName();
    });
}
并且绑定到UI的元素上,例如:

The name is <span data-bind="text: fullName"></span>
… 不管 firstName 还是 lastName 改变,全称fullName都会自动更新(不管谁改变,执行函数都会调用一次,不管改变成什么,他的值都会更新到UI或者其他自动计算属性上)。


完整代码:

<body>
The firstName is <input data-bind="value: firstName"><p>
The lastName is <input data-bind="value: lastName"><p>
The name is <span data-bind="text: fullName"></span>
</body>
</html>
<script type="text/javascript">
function AppViewModel() {
   var self = this;
   self.firstName = ko.observable('Bob');
   self.lastName = ko.observable('Smith');
   //下面这个属性依赖上面的2个属性存在
   self.fullName = ko.computed(function(){
      return self.firstName() + " " + self.lastName();
   });
}
ko.applyBindings(new AppViewModel());
</script>
其中的<input data-bind="value: ...">也是一种绑定方式,将在下文介绍。