入门

监控属性

使用内置绑定

控制文本和外观

绑定逻辑控制

处理表单属性

解析模板

高级应用

插件

更多信息

监控数组(Observable Arrays)

如果你要探测和响应一个对象的变化,你应该用observables。如果你需要探测和响应一个集合对象的变化,你应该用 observableArray 。在很多场景下,它都非常有用,比如你要在UI上需要显示/编辑的一个列表数据集合,然后对集合进行添加和删除。

If you want to detect and respond to changes on one object, you’d use observables. If you want to detect and respond to changes of a collection of things, use an observableArray. This is useful in many scenarios where you’re displaying or editing multiple values and need repeated sections of UI to appear and disappear as items are added and removed.

例子

  1. var myObservableArray = ko.observableArray(); // Initially an empty array
  2. myObservableArray.push('Some value'); // Adds the value and notifies observers

请参阅如何使用 observableArray 绑定到UI并让用户修改他们the simple list example.

To see how you can bind the observableArray to a UI and let the user modify it, see the simple list example.

关键点:监控数组跟踪的是数组的对象,而不是这些对象自身的状态。

简单说,将一对象放在 observableArray 里不会使这个对象本身的属性变化可监控的。当然你自己也可以声明这个对象的属性为observable的,但它就成了一个依赖监控对象了。一个 observableArray 仅仅监控他拥有的对象,并在这些对象添加或者删除的时候发出通知。

Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.

预加载一个监控数组(observableArray)

如果你想让你的监控数组在开始的时候就有一些初始值,那么在声明的时候,你可以在构造器里加入这些初始对象。例如:

If you want your observable array not to start empty, but to contain some initial items, pass those items as an array to the constructor. For example,

  1. // This observable array initially contains three objects
  2. var anotherObservableArray = ko.observableArray([
  3. { name: "Bungle", type: "Bear" },
  4. { name: "George", type: "Hippo" },
  5. { name: "Zippy", type: "Unknown" }
  6. ]);

从监控数组(observableArray)里读取信息

一个 observableArray 其实就是一个 observable的监控对象,只不过他的值是一个数组 (observableArray还加了很多其他特性,稍后介绍)。所以你可以像获取普通的 observableArray 的值一样,只需要调用无参函数就可以获取自身的值了。 例如,你可以像下面这样获取它的值:

Behind the scenes, an observableArray is actually an observable whose value is an array (plus, observableArray adds some additional features I’ll describe in a moment). So, you can get the underlying JavaScript array by invoking the observableArray as a function with no parameters, just like any other observable. Then you can read information from that underlying array. For example,

  1. alert('The length of the array is ' + myObservableArray().length);
  2. alert('The first element is ' + myObservableArray()[0]);

理论上你可以使用任何原生的JavaScript数组函数来操作这些数组,但是KO提供了更好的功能等价函数observableArray,他们非常有用是因为:

Technically you can use any of the native JavaScript array functions to operate on that underlying array, but normally there’s a better alternative. KO’s observableArray has equivalent functions of its own, and they’re more useful because:

  • 兼容所有浏览器。(例如 indexOf 不能在IE8和早期版本上使用,但KO自己的 indexOf 可以在所有浏览器上使用)
  • They work on all targeted browsers. (For example, the native JavaScript indexOf function doesn’t work on IE 8 or earlier, but KO’s indexOf works everywhere.)
  • 在数组操作函数方面(例如 push and splice),KO自己的方式可以自动触发依赖跟踪,并且通知所有的订阅者它的变化,然后让UI界面也相应的自动更新。
  • For functions that modify the contents of the array, such as push and splice, KO’s methods automatically trigger the dependency tracking mechanism so that all registered listeners are notified of the change, and your UI is automatically updated.
  • 语法更方便,调用KO的 push 方法,只需要这样写: myObservableArray.push(…)。 比如原生数组的 myObservableArray().push(…)好用多了。
  • The syntax is more convenient. To call KO’s push method, just write myObservableArray.push(…). This is slightly nicer than calling the underlying array’s push method by writing myObservableArray().push(…).

下面讲解的均是 observableArray 的读取和写入的相关函数。

The rest of this page describes observableArray’s functions for reading and writing array information.

indexOf

indexOf 函数返回的是第一个等于你参数数组项的索引。例如: myObservableArray.indexOf('Blah') 将返回以0为第一个索引的第一个等于 Blah的数组项的索引。如果没有找到相等的,将返回 -1

The indexOf function returns the index of the first array item that equals your parameter. For example, myObservableArray.indexOf('Blah') will return the zero-based index of the first array entry that equals Blah, or the value -1 if no matching value was found.

slice

slice 函数是 observableArray 相对于JavaScript 原生函数 slice 的等价函数(返回给定的从开始索引到结束索引之间所有的对象集合)。 调用 myObservableArray.slice(…) 等价于调用JavaScript原生函数 myObservableArray().slice(…))。

The slice function is the observableArray equivalent of the native JavaScript slice function (i.e., it returns the entries of your array from a given start index up to a given end index). Calling myObservableArray.slice(…) is equivalent to calling the same method on the underlying array (i.e., myObservableArray().slice(…)).

操作observableArray

observableArray 展现的是数组对象相似的函数并通知订阅者的功能。

observableArray exposes a familiar set of functions for modifying the contents of the array and notifying listeners.

pop, push, shift, unshift, reverse, sort, splice

所有这些函数都是和JavaScript数组原生函数等价的,唯一不同的数组改变可以通知订阅者:

All of these functions are equivalent to running the native JavaScript array functions on the underlying array, and then notifying listeners about the change:

  • myObservableArray.push('Some new value') 在数组末尾添加一个新项

myObservableArray.push('Some new value') adds a new item to the end of array

  • myObservableArray.pop() 删除数组最后一个项并返回该项

myObservableArray.pop() removes the last value from the array and returns it

  • myObservableArray.unshift('Some new value') 在数组头部添加一个项

myObservableArray.unshift('Some new value') inserts a new item at the beginning of the array

  • myObservableArray.shift() 删除数组头部第一项并返回该项

myObservableArray.shift() removes the first value from the array and returns it

  • myObservableArray.reverse() 翻转整个数组的顺序

myObservableArray.reverse() reverses the order of the array

  • myObservableArray.sort() 给数组排序

myObservableArray.sort() sorts the array contents.

  • 默认情况下,是按照字符排序(如果是字符)或者数字排序(如果是数字)。
  • By default, it sorts alphabetically (for strings) or numerically (for numbers).
  • 你可以排序传入一个排序函数进行排序,该排序函数需要接受2个参数(代表该数组里需要比较的项),如果第一个项小于第二个项,返回-1,大于则返回1,等于返回0。例如:用lastname给person排序,你可以这样写: myObservableArray.sort(function(left, right) { return left.lastName == right.lastName ? 0 : (left.lastName < right.lastName ? -1 : 1) })
  • Optionally, you can pass a function to control how the array should be sorted. Your function should accept any two objects from the array and return a negative value if the first argument is smaller, a positive value is the second is smaller, or zero to treat them as equal. For example, to sort an array of ‘person’ objects by last name, you could write myObservableArray.sort(function(left, right) { return left.lastName == right.lastName ? 0 : (left.lastName < right.lastName ? -1 : 1) })
  • myObservableArray.splice() 删除指定开始索引和指定数目的数组对象元素。例如 myObservableArray.splice(1, 3) 从索引1开始删除3个元素(第2,3,4个元素)然后将这些元素作为一个数组对象返回。

myObservableArray.splice() removes and returns a given number of elements starting from a given index. For example, myObservableArray.splice(1, 3) removes three elements starting from index position 1 (i.e., the 2nd, 3rd, and 4th elements) and returns them as an array.

更多observableArray 函数的信息,请参考等价的 standard JavaScript array functions

remove 和 removeAll

remove and removeAll

observableArray 添加了一些JavaScript数组默认没有但非常有用的函数:

observableArray adds some more useful methods that aren’t found on JavaScript arrays by default:

  • myObservableArray.remove(someItem) 删除所有等于 someItem的元素并将被删除元素作为一个数组返回
  • myObservableArray.remove(someItem) removes all values that equal someItem and returns them as an array
  • myObservableArray.remove(function(item) { return item.age < 18 }) 删除所有 age 属性小于18的元素并将被删除元素作为一个数组返回
  • myObservableArray.remove(function(item) { return item.age < 18 }) removes all values whose age property is less than 18, and returns them as an array
  • myObservableArray.removeAll(['Chad', 132, undefined]) 删除所有等于 'Chad', 123, or undefined and returns them as an array
  • myObservableArray.removeAll(['Chad', 132, undefined]) removes all values that equal 'Chad', 123, or undefined 的元素并将被删除元素作为一个数组返回

destroy和destroyAll(注:通常只和Ruby on Rails开发者有关)

destroy and destroyAll (Note: Usually relevant to Ruby on Rails developers only)

destroydestroyAll 函数是为Ruby on Rails开发者方便使用为开发的:

The destroy and destroyAll functions are mainly intended as a convenience for developers using Ruby on Rails:

  • myObservableArray.destroy(someItem) 找出所有等 someItem 的元素并给他们添加一个属性 _destroy,并赋值为true
  • myObservableArray.destroy(someItem) finds any objects in the array that equal someItem and gives them a special property called _destroy with value true
  • myObservableArray.destroy(function(someItem) { return someItem.age < 18 }) 找出所有 age 属性小于18的元素并给他们添加一个属性 _destroy ,并赋值为 true
  • myObservableArray.destroy(function(someItem) { return someItem.age < 18 }) finds any objects in the array whose age property is less than 18, and gives those objects a special property called _destroy with value true
  • myObservableArray.destroyAll(['Chad', 132, undefined]) 找出所有等于 'Chad', 123, or undefined 的元素并给他们添加一个属性 _destroy ,并赋值为 true
  • myObservableArray.destroyAll(['Chad', 132, undefined]) finds any objects in the array that equal 'Chad', 123, or undefined and gives them a special property called _destroy with value true

那么, _destroy 是做什么用的?正如我提到的,这只是为Rails 开发者准备的。在Rails 开发过程中,如果你传入一个JSON对象,Rails 框架会自动转换成ActiveRecord对象并且保存到数据库。Rails 框架知道哪些对象以及在数据库中存在,哪些需要添加或更新, 标记 _destroytrue 就是告诉框架删除这条记录。

So, what’s this _destroy thing all about? As I mentioned, it’s only really interesting to Rails developers. The convention in Rails is that, when you pass into an action a JSON object graph, the framework can automatically convert it to an ActiveRecord object graph and then save it to your database. It knows which of the objects are already in your database, and issues the correct INSERT or UPDATE statements. To tell the framework to DELETE a record, you just mark it with _destroy set to true.

注意的是:在KO render一个 foreach 模板的时候,会自动隐藏带有 _destroy 属性并且值为 true的元素。所以如果你的“delete”按钮调用 destroy(someItem) 方法的话,UI界面上的相对应的元素将自动隐藏,然后等你提交这个JSON对象到Rails上的时候,这个元素项将从数据库删除(同时其它的元素项将正常的插入或者更新)。

Note that when KO renders a foreach binding, it automatically hides any objects marked with _destroy equal to true. So, you can have some kind of “delete” button that invokes the destroy(someItem) method on the array, and this will immediately cause the specified item to vanish from the visible UI. Later, when you submit the JSON object graph to Rails, that item will also be deleted from the database (while the other array items will be inserted or updated as usual).

(c) knockoutjs.com