本节主要涉及到3个内容:

1. 监控属性 Observables

(这个用的比较多,但是其本身使用比较简单,唯一需要注意就是,它监控的对象是一个方法,所以取值和设置值的时候容易混淆)

2. 计算属性  Computed Observable

(这个在新增计算列,或者对字段属性值的读写进行验证、转换时特别有用)

3. 监控属性数组 Observable Arrays

(这个用的较少,一开始不需要太深入,毕竟直接绑定数组进行简单显示的情况不多)

 

下面分别简单介绍一下各自的用法。

 

1. 监控属性Observables

 

KO最重要的一个属性就是当View Model发生变化时能够自动的更新UI界面。KO是如何能够知道你的View Model已经发生改变了呢?答案是:你需要将你的model属性声明成observable的, 因为它是非常特殊的JavaScript 对象,能够通知用户它的改变以及自动检测依赖关系。

例如:重写上节例子中的View Model为以下代码:

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

你根本不需要对View进行更改,所有的data-bind语法依然正常工作。所不同的是,现在它能够自动检测变化,并通知它自动更新界面(View)。

 

Reading and writing observables  -  关于监控属性的读写操作

 

关于监控属性本身使用比较简单,唯一需要注意的是,为了兼容IE,它监控的对象都是方法,所以在取值和设置值需要注意下,刚开始使用时往往会忽略这点。

并不是所有的浏览器都支持JavaScript的getters and setters (比如IE),所以,为了兼容,ko.observable监控的对象都是方法。

1、读取当前监控的属性值,只需要直接调用observable(不需要参数),在这个例子当中,调用myViewModel.personName()将会返回'Bob',调用myViewModel.personAge() 将会返回'123'

2、写一个新值到监控属性上,调用observable方法,将要写的值作为一个参数传入即可。例如,调用myViewModel.personName('Mary') 将会把名称改变成 'Mary'。

3、一次性改变Model对象监控的多个属性值,你可以使用链式方法。例如:myViewModel.personName('Mary').personAge(50) 将会把名称改变成'Mary'将年龄设置为 50.

监控属性最重要的一点就是可以随时监控,也就是说,其他代码可以告诉它哪些是需要通知发生变化的。这就是为什么KO会有如此多的内置绑定语法。所以,当你在页面中编写data-bind="text: personName",text 会绑定注册到自身,当personName发生变化时,它能够立即得到通知。

当你通过调用 myViewModel.personName('Mary') 将名称的值改变成为'Mary'时,text绑定会自动更新新值到其对应的DOM对象元素上,这就是为什么改变数据模型能够自动刷新View页面。

 

2. 计算属性  Computed Observable

 

如果你已经有了一个监控属性 firstName和lastName,如果你想显示全名该怎么做呢?这个时候你就可以通过计算属性来实现,这个方法依赖于一个或多个监控属性,如果任何依赖对象发生改变他们就会跟着改变。

例如,下面的 view model:

 

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

 

你可以添加一个计算属性来返回全名,例如:

function AppViewModel() {
    // ... leave firstName and lastName unchanged ...

    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);
}

下面你就可以将它绑定到UI对象上了,如:

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

当firstName或者lastName 变化,它将会随时更新(当依赖关系发生变化,你的计算函数就会被调用,并且它的值都会更新到UI对象或其他的依赖属性上去)。

 

关于计算属性的读和写

计算属性通常情况下是只读的,你可能会比较惊讶,怎么可能让计算属性变的可写。你仅仅只需要提供一个回调函数来实现值的写入。

然后你可以把这个可写的计算属性当成一个普通的监控属性来使用,通过你自定义的逻辑来实现它的读和写。这个强大的功能可以拓宽我们对KO的使用范围,你可以通过链式语法在一个View Model上传入多个监控属性或者计算属性,例如:

myViewModel.fullName('Joe Smith').age(50)

 

下面介绍几使用个例子,

示例一:分解用户输入

function MyViewModel() {
    this.firstName = ko.observable('Planet');
    this.lastName = ko.observable('Earth');

    this.fullName = ko.computed({
        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
    });
}

ko.applyBindings(new MyViewModel());

示例二:值转换

function MyViewModel() {
    this.price = ko.observable(25.99);

    this.formattedPrice = ko.computed({
        read: function () {
            return '$' + this.price().toFixed(2);
        },
        write: function (value) {
            // Strip out unwanted characters, parse as float, then write the raw data back to the underlying "price" observable
            value = parseFloat(value.replace(/[^\.\d]/g, ""));
            this.price(isNaN(value) ? 0 : value); // Write to underlying storage
        },
        owner: this
    });
}

ko.applyBindings(new MyViewModel());

View Code

示例三:筛选和验证用户输入

function MyViewModel() {
    this.acceptedNumericValue = ko.observable(123);
    this.lastInputWasValid = ko.observable(true);

    this.attemptedValue = ko.computed({
        read: this.acceptedNumericValue,
        write: function (value) {
            if (isNaN(value))
                this.lastInputWasValid(false);
            else {
                this.lastInputWasValid(true);
                this.acceptedNumericValue(value); // Write to underlying storage
            }
        },
        owner: this
    });
}

ko.applyBindings(new MyViewModel());

View Code

 

3. 监控属性数组 Observable Arrays

如果你想发现并响应一个对象的改变,就应该用监控属性(observables)。如果你想发现并响应一个集合的变化,就该用监控属性数组(observableArray)。监控属性数组在 显示或编辑多个值 以及 对界面的一部分重复显示或隐藏(如添加删除条目)等多种情况下 都是很有用的。

 

如果我们想要使用Knockoutjs表示多个值的话我们可以使用数组监控(Observable Arrays)来表示,形式如下:

var myObservableArray = ko.observableArray();  
 myObservableArray.push('Some value');

在第一行我们实例化了一个数组,在第二行我们向此数组中添加了一条记录,正如我们看到的那样,往数组中添加数组我们使用push方法。当然我们也可以在初始化数组的时候为其赋初值,代码如下:

var anotherObservableArray = ko.observableArray([  { 
   name: "Bungle", type: "Bear" }, { 
   name: "George", type: "Hippo" }, { 
   name: "Zippy", type: "Unknown" } ]);

 

最后附上 Knockoutjs 数组常用的方法如下:

 

(1)、myObservableArray.push('Some new value'):增加一个新的元素

(2)、myObservableArray.pop():删除一个元素,并返回其值

(3)、myObservableArray.unshift('Some new value'):在数组的开始处增加一个新的元素

(4)、myObservableArray.shift():删除数组的第一个元素,并返回其值

(5)、myObservableArray.reverse():反转数组的顺序

(6)、myObservableArray.sort():数组排序。排序规则可以由用户自己定义也可以使用默认,默认情况下按照字母顺序或者数字的顺序进行排序。自己定义排序规则时需要接收数组 中的两个元素,并且需要返回一个数值,当此值小于0时表示第一个元素较小,当此值大于0时,表示第二个元素较小,当等于0时表示两个元素相等。

(7)、myObservableArray.splice():数组截取。例如:myObservableArray.splice(1, 3),代表从数组的第一个元素开始,截取三个元素,并且将他们作为数组返回。