前言
1.創建一個ViewModel
<script type="text/javascript"> //1.創建一個ViewModel var myViewModel = { personName:'aehyok', personAge:25 }; </script>
2.為ViewModel創建一個聲明式綁定的簡單的View
The name is <span data-bind="text:personName"></span>
3.激活Knockout
|
1
|
ko.applyBindings(myViewModel);
|
4.查看運行效果

Observables監控屬性
現在已經知道如何創建一個簡單的view model並且通過binding顯示它的屬性了。但是KO一個重要的功能是當你的view model改變的時候能自動更新你的界面。當你的view model部分改變的時候KO是如何知道的呢?答案是:你需要將你的model屬性聲明成observable的, 因為它是非常特殊的JavaScript objects,能夠通知訂閱者它的改變以及自動探測到相關的依賴。
例如:將上述的例子修改為
|
1
2
3
4
|
var
myViewModel = {
personName: ko.observable(
'aehyok'
),
personAge: ko.observable(25)
};
|
你根本不需要修改view – 所有的data-bind語法依然工作,不同的是他能監控到變化,當值改變時,view會自動更新。
監控屬性的讀操作(read)
|
1
2
|
///監控屬性的讀操作(read)
alert(myViewModel.personAge);
|
監控屬性的寫操作(write)
|
1
2
|
///監控屬性的寫操作(write)
myViewModel.personName(
"aehyok-Test"
);
|
Dependent Observables依賴監控屬性
如果你已經有了監控屬性firstName和lastName,你想顯示全稱怎么辦? 這就需要用到依賴監控屬性了 – 這些函數是一個或多個監控屬性, 如果他們的依賴對象改變,他們會自動跟着改變。
例如:繼續在上面的ViewModel中添加兩個屬性 firstName和lastName
|
1
2
3
4
5
6
|
var
myViewModel = {
personName: ko.observable(
'aehyok'
),
personAge: ko.observable(25),
firstName: ko.observable(
'aehyok'
),
lastName: ko.observable(
'Leo'
)
};
|
並且添加一個依賴監控屬性,來返回姓名的全稱
|
1
2
3
4
|
///依賴監控屬性
myViewModel.fullName = ko.dependentObservable(function () {
return
this
.firstName() +
" "
+
this
.lastName();
}, myViewModel);
|
並且綁定到View視圖界面上的元素
The fullname is <span data-bind="text: fullName"></span>
不管firstName還是lastName改變,全稱fullName都會自動更新(不管誰改變,執行函數都會調用一次,不管改變成什么,他的值都會更新到UI或者其他依賴監控屬性上)。
優化上面fullname的監控屬性
|
1
2
3
4
|
var
viewModel = {
firstName: ko.observable(
"aehyok"
),
lastName:ko.observable(
"Leo"
)
};
|
對fullName的依賴監控屬性進行調整
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
viewModel.fullName = ko.dependentObservable({
read:function() {
return
this
.firstName() +
" "
+
this
.lastName();
},
write:function(value) {
var
lastSpacePos = value.lastIndexOf(
" "
);
if
(lastSpacePos>0) {
this
.firstName(value.substring(0, lastSpacePos));
this
.lastName(value.substring(lastSpacePos + 1));
}
},
owner: viewModel
});
|
這個例子里,寫操作的callback接受寫入的值,把值分離出來,分別寫入到“firstName”和“lastName”上。 你可以像普通情況一樣將這個view model綁定到DOM元素上,如下:
|
1
2
3
|
<p>First name: <span data-bind=
"text: firstName"
></span></p>
<p>Last name: <span data-bind=
"text: lastName"
></span></p>
<h2>Hello, <input data-bind=
"value: fullName"
/>!</h2>
|
然后運行在文本框上錄入會看到如下效果

上面的view model演示的是通過一個簡單的參數來初始化依賴監控屬性。你可以給下面的屬性傳入任何JavaScript對象:
1. read — 必選,一個用來執行取得依賴監控屬性當前值的函數。
2.write — 可選,如果聲明將使你的依賴監控屬性可寫,別的代碼如果這個可寫功能寫入新值,通過自定義邏輯將值再寫入各個基礎的監控屬性上。
3.owner — 可選,如果聲明,它就是KO調用read或write的callback時用到的this。
Value轉換器
有時候你可能需要顯示一些不同格式的數據,從基礎的數據轉化成顯示格式。比如,你存儲價格為float類型,但是允許用戶編輯的字段需要支持貨幣單位和小數點。你可以用可寫的依賴監控屬性來實現,然后解析傳入的數據到基本 float類型里:
|
1
2
3
4
5
6
7
8
9
10
|
viewModel.formattedPrice=ko.dependentObservable({
read:function () {
return
"$"
+
this
.price().toFixed(2);
},
write:function(value) {
value = parseFloat(value.replace(/[^\.\d]/g,
""
));
this
.price(isNaN(value) ? 0 : value);
},
owner:viewModel
});
|
然后綁定到textbox上面
|
1
|
<p>Enter bid price: <input data-bind=
"value: formattedPrice"
/></p>
|
所以,不管用戶什么時候輸入新價格,輸入什么格式,text box里會自動更新為帶有2位小數點和貨幣符號的數值。這樣用戶可以看到你的程序有多聰明,來告訴用戶只能輸入2位小數,否則的話自動刪除多余的位數,當 然也不能輸入負數,因為write的callback函數會自動刪除負號。
過濾並驗證用戶輸入
繼續在上面的ViewModel中添加兩個屬性
|
1
2
3
4
5
6
7
|
var
viewModel = {
firstName: ko.observable(
"aehyok"
),
lastName: ko.observable(
"Leo"
),
price: ko.observable(22.466),
acceptedNumericValue: ko.observable(123),
lastInputWasValid: ko.observable(
true
)
};
|
然后添加一個依賴監控屬性
|
1
2
3
4
5
6
7
8
9
10
11
12
|
viewModel.attemptedValue = ko.dependentObservable({
read: viewModel.acceptedNumericValue,
write: function (value) {
if
(isNaN(value)) {
this
.lastInputWasValid(
false
);
}
else
{
this
.lastInputWasValid(
true
);
this
.acceptedNumericValue(value);
}
},
owner:viewModel
});
|
進行綁定View視圖界面元素
|
1
2
|
<p>Enter a numeric value: <input data-bind=
"value: attemptedValue"
/></p>
<div data-bind=
"visible: !lastInputWasValid()"
>That's not a number!</div>
|
現在,acceptedNumericValue 將只接受數字,其它任何輸入的值都會觸發顯示驗證信息,而會更新acceptedNumericValue。
前言
如果你要探測和響應一個對象的變化,你應該用observables。
如果你需要探測和響應一個集合對象的變化,你應該用observableArray 。
在很多場景下,它都非常有用,比如你要在UI上需要顯示/編輯的一個列表數據集合,然后對集合進行添加和刪除。
使用observables數組
1.簡單舉例
<script type="text/javascript"> var myObservableArray = ko.observableArray(); ///初始化一個空的數組 myObservableArray.push("Some Value"); ///向數組中添加一個項 </script>
2.關鍵點:監控數組跟蹤的是數組里的對象,而不是這些對象自身的狀態。
簡單說,將一對象放在observableArray 里不會使這個對象本身的屬性變化可監控的。當然你自己也可以聲明這個對象的屬性為observable的,但它就成了一個依賴監控對象了。一個 observableArray 僅僅監控他擁有的對象,並在這些對象添加或者刪除的時候發出通知。
3.預加載一個監控數組observableArray
如果你想讓你的監控數組在開始的時候就有一些初始值,那么在聲明的時候,你可以在構造器里加入這些初始對象。例如:
var anotherObservableArray = ko.observableArray([ { name: "Bungle", type: "Bear" }, { name: "George", type: "Hippo" }, { name: "Zippy", type: "Unknown" } ]);
4.從observableArray里讀取信息
一個observableArray其實就是一個observable的監控對象,只不過他的值是一個數組(observableArray還加了 很多其他特性,稍后介紹)。所以你可以像獲取普通的observable的值一樣,只需要調用無參函數就可以獲取自身的值了。 例如,你可以像下面這樣獲取它的值:
alert('The length of the array is ' + myObservableArray().length); alert('The first element is ' + myObservableArray()[0]);
理論上你可以使用任何原生的JavaScript數組函數來操作這些數組,但是KO提供了更好的功能等價函數,他們非常有用是因為:
A:兼容所有瀏覽器。(例如indexOf不能在IE8和早期版本上使用,但KO自己的indexOf 可以在所有瀏覽器上使用)
B:在數組操作函數方面(例如push和splice),KO自己的方式可以自動觸發依賴跟蹤,並且通知所有的訂閱者它的變化,然后讓UI界面也相應的自動更新。
C:語法更方便,調用KO的push方法,只需要這樣寫:myObservableArray.push(...)。 比如原生數組的myObservableArray().push(...)好用多了。
5.IndexOf和slice
indexOf 函數返回的是第一個等於你參數數組項的索引。例如:myObservableArray.indexOf('Blah')將返回以0為第一個索引的第一個等於Blah的數組項的索引。如果沒有找到相等的,將返回-1。
slice函數是observableArray相對於JavaScript 原生函數slice的等價函數(返回給定的從開始索引到結束索引之間所有的對象集合)。 調用myObservableArray.slice(...)等價於調用JavaScript原生函數(例 如:myObservableArray().slice(...))。
6.操作observableArray
observableArray 展現的是數組對象相似的函數並通知訂閱者的功能。
pop, push, shift, unshift, reverse, sort, splice
所有這些函數都是和JavaScript數組原生函數等價的,唯一不同的數組改變可以通知訂閱者:
myObservableArray.push('Some new value');// 在數組末尾添加一個新項 myObservableArray.pop();// 刪除數組最后一個項並返回該項 myObservableArray.unshift('Some new value');// 在數組頭部添加一個項 myObservableArray.shift();// 刪除數組頭部第一項並返回該項 myObservableArray.reverse();// 翻轉整個數組的順序 myObservableArray.sort();// 給數組排序
默認情況下,是按照字符排序(如果是字符)或者數字排序(如果是數字)。
你可以排序傳入一個排序函數進行排序,該排序函數需要接受2個參數(代表該數組里需要比較的項),如果第一個項小於第二個項,返回-1,大於則返回1,等於返回0。例如:用lastname給person排序,你可以這樣寫:
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個元素)然后將這些元素作為一個數組對象返回。
更多observableArray 函數的信息,請參考等價的JavaScript數組標准函數。
7.remove和removeAll
observableArray 添加了一些JavaScript數組默認沒有但非常有用的函數:
myObservableArray.remove(someItem);// 刪除所有等於someItem的元素並將被刪除元素作為一個數組返回 myObservableArray.remove(function (item) { return item.age < 18;}) ;//刪除所有age屬性小於18的元素並將被刪除元素作為一個數組返回 myObservableArray.removeAll(['Chad', 132, undefined]);//刪除所有等於'Chad', 123, or undefined的元素並將被刪除元素作為一個數組返回

