这篇文章主要用于记录学习Working with observable arrays的测试和体会。
Observable主要用于单一个体的修改订阅,当我们在处理一堆个体时,当UI需要重复显示一些样式相同的元素时,这些数据的绑定就需要依靠observable arrays。
特别需要注意的一点是,observable arrays关注的是数组中元素整体的变化(包括增加元素,删减元素,元素顺序的改变等等),而不是元素个体的变化(元素内部某些部分的改变)。
我们可以在js文件中创建一个observable array并初始化其中的一些元素:
1 var myObservableArray = ko.observableArray([ 2 { firstName: "Kazusa", lastName: "Touma" }, 3 { firstName: "Chiaki", lastName: "Izumi" }, 4 { firstName: "Yuki", lastName: "Nagato" } 5 ]);
按照文档的原话:an observableArray
is actually an observable whose value is an array。也就是说一个observableArray实际上就是一个observable,只不过这个observable的值是一个数组,而不是一个字符串或是数字等其他类型。在上一篇文章中,我们也可以观察到,在调用或者是修改observable的值得时候,我们要把它当做一个函数来使用,即在identifier之后要增加一个括号,这一法则也适用于observableArray(毕竟它本质上就是一个observable,事实上我在想为什么knockout不直接把observableArray的构造函数整合到observable之中去,可能是考虑到所有的方法不一样吧,也可能是为了在概念上更为清晰一些)。为了获取和修改observableArray的值或是其中的元素,我们创建了几个p元素用于显示:
1 <p>The length of observableArray is: <span id="lengthOfArray"></span></p> 2 <p>The second element of observableArray is: <span id="secondElement"></span></p> 3 <p>The changed element: <span id="changedElement"></span></p>
而在js文件中,我们做了以下操作:
1 $("#lengthOfArray").text(myObservableArray().length); 2 $("#secondElement").text(myObservableArray()[1].firstName); 3 myObservableArray()[2].lastName = "Charlie"; 4 $("#changedElement").text(myObservableArray()[2].lastName);
最后页面显示如下:
一般说来,我们能够使用类似javascript中的最基本的数组操作方法来对observableArray进行操作,但是KO的observableArray拥有更为强大的特性,归纳为以下三点:
- 它们能够在所有浏览器上使用(例如javascript的indexof方法不能再IE8以前的浏览器上使用,而KO的indexof方法则可以使用)。
- 对于修改数组内容的方法,比如push或是splice,KO的方法会自动触发依赖跟踪机制并使得所有的订阅者和UI进行自动的改变。
- KO的方法在调用起来更为简洁,比如push方法只需要写成myObservableArray.push(...)而不是原先的myObservableArray().push(...)。
对于第三条我是存在一些疑问的:哪些方法可以省略括号,哪些方法不能省略括号呢?(至少length就不能,大概是因为length算作属性而不算方法的原因?)目前基本猜测是方法可以省略括号,而属性或元素不行。
之后的文档主要介绍的是读写数组信息所能用到的一些函数。为了能够更为直观地展现我的observableArray数组,我对js文件做了以下修改:
1 var i, length; 2 for (i = 0, length = myObservableArray().length; i < length; i++) { 3 $("<p></p>").appendTo($("p:last")); 4 $("p:last").text("First Name: " + myObservableArray()[i].firstName + "; Last Name: " + myObservableArray()[i].lastName); 5 }
Indexof方法可以返回数组中等于你所提供的参数的第一个元素的索引值,如果数组中不存在满足条件的元素,则返回-1,相应的js部分如下:
1 $("#indexOfChiaki").text(myObservableArray.indexOf("Chiaki")); 2 $("#indexOfCharlie").text(myObservableArray.indexOf("Charlie"));
相应的html部分如下:
1 <p>The index of Chiaki is: <span id="indexOfChiaki"></span></p> 2 <p>The index of Charlie is: <span id="indexOfCharlie"></span></p>
效果如下:
Slice方法用于返回数组中指定范围的元素值(如果省略第二个参数,则默认从第一个参数的位置到数组结尾),相应的js部分如下:
1 $("#testForSlice").text(myObservableArray.slice(2, 5));
相应的html部分如下:
1 <p>Test for slice function: <span id="testForSlice"></span></p>
效果如下:
假定我们的observableArray的元素就以上图为初始状态,接下来对pop、push、shift等方法进行测试。每个方法的效果图都在左边附加了原先的数组样式。
push用于在数组末尾添加指定的元素,相应的js部分如下:
1 myObservableArray.push("Charlie");
效果如下:
pop方法用于删除并返回数组的最后一个元素,相应的js部分如下:
1 var test = myObservableArray.pop(); 2 alert(test);
效果如下:
unshift方法用于在数组首部添加一个指定的元素,相应的js部分如下:
1 myObservableArray.unshift("Charlie");
效果如下:
shift方法用于删除并返回数组开头的元素,相应的js部分如下:
1 var test = myObservableArray.shift(); 2 alert(test);
效果如下:
reverse方法用于倒置数组的顺序,相应的js部分如下:
1 myObservableArray.reverse();
效果如下:
sort方法用于对数组进行排序,默认的排序规则是按照字母的顺序排序,相应的js部分如下:
1 myObservableArray.sort();
效果如下:
另外,sort方法也可以自定义排序的方式,比如自定义一个按字母倒序排列的方法:
1 myObservableArray.sort(function(left, right) { 2 return left === right ? 0 : (left < right ? 1 : -1); 3 });
效果如下:
关于sort自定义的排序方法,我是有一点疑问的,提供给function的两个参数left和right是怎样实现排序的?比较后所需要返回的正负数值又是如何应用到排序中去的?也许这些可以从knockout的源代码中找到答案,可留作以后研究。
splice方法删除并返回数组中从指定位置开始的指定数量的元素,它的第一个参数是指定的index的值,第二个参数则是需要删除的元素个数,相应的js部分如下:
1 var test = myObservableArray.splice(1, 3); 2 alert(test);
效果如下:
对于更为详尽的array方面可以使用的方法,MDN上有详尽的文档。
以下的方法都是javascript的默认方法中所没有的KO的新方法。
为了能够测试remove等方法的效果,我将数组元素变成如下形式:
remove方法可以删除等于指定值的元素并将它们以数组的方式返回,相应的js部分如下:
1 var test = myObservableArray.remove("Chiaki"); 2 alert(test);
效果如下:
也可以在remove中自定义删除的条件,相应的js部分如下:
1 var test = myObservableArray.remove(function(item) { 2 return item.length <= 5; 3 }); 4 alert(test);
效果如下:
removeAll方法用于删除等于指定数组中某一元素的元素并将其以数组的方式返回,相应的js部分如下:
1 var test = myObservableArray.removeAll(["Chiaki", "Kazusa", "Charlie"]); 2 alert(test);
效果如下:
如果在removeAll方法中不添加参数,则将会删除整个数组并返回,这里不再演示。
由于destroy和destroyAll方法主要是与Ruby和Rails开发相关,可以留作以后研究。
同样的,observableArray也可以调用extend方法中的rateLimit属性来指定延时,留作之后激活bindings时再测试。
Knockout学习笔记(二),布布扣,bubuko.com