2.通过监控数组工作
1. 监控数组
如果你想检测或者响应一个对象的改变,你用observables
。如果你想检测和响应一个集合的改变,使用observableArray。这个在很多情况下都非常有用,比如当你在显示或者编辑多个值而且需要重复的UI部分通过添加和移除来显示/隐藏项。
例子:
var myObservableArray = ko.observableArray(); // 初始化空数组
myObservableArray.push('Some value'); // 添加值并通知监控
为了看怎样绑定observableArray到一个UI界面,同时我们可以修改它,看简单列表
的例子。
2. 关键点:一个监控数组对象跟踪数组里面有哪些对象,而不是这些对象的状态
简单地把一个对象放进一个observableArray
并不会让所有对象自身的属性被监控。当然,如果你想,你可以让这些属性被监控,一个observableArray
仅仅跟踪它存有哪些对象和在添加和移除对象的时候通知监听器。
3. 尝鲜observableArray
如果你希望你的observable数组不是开始为空,而是包含一些初始项,将这些项作为一个数组传递给构造函数。 例如,
// 监控数组默认包含三个对象
var anotherObservableArray = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]);
4. 读取observableArray的信息
在实现上,observableArray实际上是一个observable对象,其值是一个数组(如下所述,observableArray还添加了一些附加功能)。所以,你可以通过调用observableArray
作为无参函数来获取底层的JavaScript数组,就像一个监控对象。然后,您可以从该底层数组读取信息。 例如,
alert('数组长度为 ' + myObservableArray().length);
alert('第一个元素是' + myObservableArray()[0]);
技术上来讲,你可以使用任何原生JavaScript数组函数来操作这个底层数组,但有一个更好的选择。 KO的observableArray具有自己的等价函数,它们更有用,因为:
- 它们适用于所有的浏览器。 (例如,原生JavaScript 的
indexOf
函数在IE 8或更早版本上不工作,但KO的indexOf在任何地方都可以使用。) - 对于修改数组内容的函数(例如
push
和splice
),KO的方法会自动触发依赖关系跟踪机制,以便向所有已注册的侦听器通知更改,并且您的UI会自动更新。 - 语法更方便。 要调用KO的
push
方法,只需写myObservableArray.push(...)
。 这比通过编写myObservableArray().push(...)
调用原生javascript数组的push方法稍微好一点。
此节剩下的内容是描述observableArray
读写数组信息的功能。
1. indexOf
indexOf函数返回等于您的参数的第一个数组项的索引。 例如,myObservableArray.indexOf('Blah')
将返回等于Blah的第一个数组实体从零开始的索引,如果没有找到匹配的值,则返回-1。
2. slice
slice函数是observableArray等价于原生 JavaScript 的slice函数(即,它会返回从你给定的开始位置和结束位置之间的数组实体,不包含结束位置的数组实体)。 调用myObservableArray.slice(...)
等价于在原生数组(myObservableArray().slice(...)
)上调用相同的方法。
5. 操作一个监控数组
observableArray暴露了一组熟悉的函数,用于修改数组的内容和通知侦听器。
1. pop, push, shift, unshift, reverse, sort, splice
所有这些函数都等价于在本地运行的JavaScript数组函数,然后通知监听器有关更改:
- push( value ) — 在数组末尾添加一个新的元素。
- pop() — 从数组里面移除最后一个元素并返回它。
- unshift( value ) — 在数组头部添加一个新的元素。
- shift() — 从数组里面移除第一个元素并返回它。
- reverse() — 颠倒数组的顺序,并返回observableArray(而不是底层数组)。
- sort() — 排序数组内容并返回observableArray
- 默认排序是字母顺序,但您可以选择传递一个函数来控制数组的排序方式。您的函数应该接受数组中的任意两个对象,如果第一个参数较小,则返回一个负值,如果第二个参数较小,则返回一个正值,如果相等则返回0。例如,要按姓氏对
person
对象数组排序,可以这样写:
- 默认排序是字母顺序,但您可以选择传递一个函数来控制数组的排序方式。您的函数应该接受数组中的任意两个对象,如果第一个参数较小,则返回一个负值,如果第二个参数较小,则返回一个正值,如果相等则返回0。例如,要按姓氏对
myObservableArray.sort(function (left, right) { return left.lastName == right.lastName ? 0 : (left.lastName < right.lastName ? -1 : 1) })
- splice() — 从给定的索引开始删除并返回给定数量的元素。 例如,
myObservableArray.splice(1,3)
删除从索引位置1开始的三个元素(即第2,第3和第4个元素),并将它们作为数组返回。
有关这些observableArray函数的更多详细信息,请参阅标准JavaScript数组函数的等价文档。
6. 移除和移除全部
observableArray
添加了一些原生javascript没有的特别有用的方法:
- remove( someItem ) — 删除所有等于someItem的值,并将它们作为数组返回。
- remove( function (item) { return item.age < 18; } ) — 删除所有age属性小于18的值,并将它们作为数组返回。
- removeAll( ['Chad', 132, undefined] ) — 删除所有等于
'Chad'
,123
或undefined
的值 ,并将它们作为数组返回。 - removeAll() — 删除所有值并将其作为数组返回。
7. 破坏和破坏所有
destroy
和destroyAll
函数主要是为了方便使用Ruby on Rails的开发人员:
- destroy( someItem)—查找数组中等于
someItem
的任何对象,并给它们一个名为_destroy
的特殊属性,赋值为true
。 - destroy( function (someItem) { return someItem.age < 18; } ) — 查找数组中
age
属性小于18的任何对象,并给这些对象一个名为_destroy
的特殊属性,赋值为true
。 - destroyAll( ['Chad', 132, undefined] ) — 查找数组中等于
'Chad'
,123
或undefined
的任何对象,并给它们一个名为_destroy
的特殊属性,赋值为true
。 - destroyAll() —为数组中的所有对象提供一个名为
_destroy
的特殊属性,赋值为true
。
那么,_destroy
是什么?对其感兴趣的仅仅只有Rails开发人员。 Rails中的约定是,当你将一个JSON对象图传递给一个action时,框架可以自动将其转换为ActiveRecord对象图,然后将其保存到数据库中。 它知道哪些对象已经在您的数据库中存在,并发出正确的INSERT或UPDATE语句。 要告诉框架删除一个记录,你只需将它标记为_destroy
设置为true
。
注意,当KO渲染foreach
绑定时,它会自动隐藏任何标记为_destroy
等于true
的对象。所以,你可以有一个“删除”按钮,调用数组上的destroy(someItem)
方法,这可以使指定的项从界面UI中立即消失。 之后,当您将JSON对象图提交到Rails时,该项也将从数据库中删除(而其他数组项可以像往常一样插入或更新)。
8. 延迟或阻止更改通知
通常情况下,一个监控数组对象只要发生改变就会立即通知订阅者。但是一个监控数组对象频繁重复改变或触发一直更新,代价会很大,通过限制或延迟监控到的更改通知,可以获得更好的性能。可以使用频率限制扩展器来完成,如下:
// 确保每50毫秒内通知改变不超过一次
myViewModel.myObservableArray.extend({ rateLimit: 50 });