Knockout v3.4.0 中文版教程-4-通过监控数组工作

时间:2021-03-25 19:11:30

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具有自己的等价函数,它们更有用,因为:

  1. 它们适用于所有的浏览器。 (例如,原生JavaScript 的indexOf函数在IE 8或更早版本上不工作,但KO的indexOf在任何地方都可以使用。)
  2. 对于修改数组内容的函数(例如pushsplice),KO的方法会自动触发依赖关系跟踪机制,以便向所有已注册的侦听器通知更改,并且您的UI会自动更新。
  3. 语法更方便。 要调用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对象数组排序,可以这样写:
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'123undefined的值 ,并将它们作为数组返回。
  • removeAll() — 删除所有值并将其作为数组返回。

7. 破坏和破坏所有

destroydestroyAll函数主要是为了方便使用Ruby on Rails的开发人员:

  • destroy( someItem)—查找数组中等于someItem的任何对象,并给它们一个名为_destroy的特殊属性,赋值为true
  • destroy( function (someItem) { return someItem.age < 18; } ) — 查找数组中age属性小于18的任何对象,并给这些对象一个名为_destroy的特殊属性,赋值为true
  • destroyAll( ['Chad', 132, undefined] ) — 查找数组中等于'Chad'123undefined的任何对象,并给它们一个名为_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 });