Knockout設計成容許你使用任何JavaScript對象做爲view model。必須view model的一些屬性是observable的,你可使用KO綁定他們到你的UI元素上,當這些observable值改變的時候,這些UI元素就會自動更新。git
絕大多數程序都須要從服務器端獲取數據,可是因爲服務器不知道observable的概念是什麼,它只支持簡單的JavaScript對象(一般是序列化之後的JSON),mapping插件可讓你很方便地將簡單JavaScript對象mapp到帶有observable值的view model。你也能夠本身寫JavaScript代碼將從服務器獲取的數據來構建 view model,mapping插件只是一種很好的替代而已。github
下載ajax
Version 2.0 (最小版本8.6kb)數組
例子:手工mapping服務器
顯示當前服務器時間和你網站上的當前用戶數。你應該使用以下的view model來表明你的這些信息:數據結構
var viewModel = {
serverTime: ko.observable(),
numUsers: ko.observable()
}
而後綁定view model到HTML元素上,以下:app
The time on the server is: <span data-bind='text: serverTime'></span>
and <span data-bind='text: numUsers'></span> user(s) are connected.
因爲view model屬性是observable的,在他們變化的時候,KO會自動更新綁定的HTML元素。函數
接下來,從服務器獲取最新的數據。或許每隔5秒你要調用一次Ajax請求(例如,使用jQuery的$.getJSON或$.ajax函授):網站
var data = getDataUsingAjax(); // Gets the data from the server
而後,服務器返回和下面類似的JSON數據:ui
{
serverTime: '2010-01-07',
numUsers: 3
}
最後,用這些數據更新你的view model(不使用mapping插件),代碼以下:
// Every time data is received from the server:
viewModel.serverTime(data.serverTime);
viewModel.numUsers(data.numUsers);
爲了使數據顯示在頁面上,全部的屬性都要像這樣寫代碼。若是你的數據結構很複雜的話(例如,包含子對象或者數組),那就維護起來就至關痛苦。mapping插件就是來讓你讓你的JavaScript簡單對象(或JSON結構)轉換成observable的view model的。
例子:使用ko.mapping
經過mapping插件建立view model,直接使用ko.mapping.fromJS函數來建立:
var viewModel = ko.mapping.fromJS(data);
它會自動將data裏全部的屬性建立成observable類型的屬性。你能夠經過ko.mapping.fromJS 函數按期從服務器獲取數據,而後更新你的view model:
// Every time data is received from the server:
ko.mapping.fromJS(data, viewModel);
如何mapping?
對象的全部屬性都被轉換成observable類型值,若是獲取的對象的值改變了,就會更新這個observable類型的值.
數組也被轉換成了observable數組,若是服務器更新改變了數組的個數,mapping插件也會添加或者刪除相應的item項,也會盡可能保持和原生JavaScript數組相同的order順序。
Unmapping
若是你想讓map過的對象轉換成原來的JavaScript對象,使用以下方式:
var unmapped = ko.mapping.toJS(viewModel);
會建立一個unmapped對象,只包含你以前map過的對象屬性,換句話說,你在view model上手工添加的屬性或者函數都會被忽略的,惟一例外的是_destroy屬性是能夠unmapped回來的,由於你從ko.observableArray裏destroy一個item項的時候會生成這個屬性。 請參考「高級用戶」小節如何配置使用。
與JSON字符串一塊兒使用
若是你的Ajax調用返回的是JSON字符串(而不是反序列化後的JavaScript對象),你可使用ko.mapping.fromJSON函數來建立或者更新你的view model。用ko.mapping.toJSON實現unmap。
使用.from/toJSON函數處理JSON字符串和使用.from/toJS函數處理JS對象是等價的。
高級用法
有時候,在使用ko.mapping.fromJS的時候,可能有必要去使用mapping的高級用法來定義mapping的詳細過程,之後定義了,之後再調用的時候就沒必要再定義了。這裏有一些情形,你可能須要使用這些option。
用法1:使用keys來使對象unique化
你有一個JavaScript對象,以下:
var data = {
name: 'Scot',
children: [
{ id: 1, name: 'Alicw' }
]
}
使用map插件,你能夠將它map到view model上(沒任何問題):
var viewModel = ko.mapping.fromJS(data);
如今,數據被更新成以下這樣:
var data = {
name: 'Scott',
children: [
{ id: 1, name: 'Alice' }
]
}
這裏發生了兩件事:name從Scot變成了Scott,children[0].name從Alicw變成了Alice。你能夠用以下代碼更新view model:
ko.mapping.fromJS(data, viewModel);
因而,name像咱們指望的同樣更新了,可是在children數組裏,子項Alicw被刪除而新項Alice被添加到數組裏。這不是咱們所指望的,咱們指望的是隻是把name從Alicw更新成Alice,不是替換整個item項。發生的緣由是,默認狀況下mapping plugin插件只是簡單地比較數組裏的兩個對象是否相等。 由於JavaScript裏{ id : 1, name : 'Alicw' }和{ id : 1, name : 'Alice' }是不相等的,因此它認爲喜歡將新項替換掉老項。
解決這個問題,你須要聲明一個key讓mapping插件使用,用來判斷一個對象是新對象仍是舊對象。代碼以下:
var mapping = {
'children': {
key: function (data) {
return ko.utils.unwrapObservable(data.id);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
這樣,每次map的時候,mapping插件都會檢查數組項的id屬性來判斷這個數組項是須要合併的仍是全新replace的。
用法2:用create自定義對象的構造器
若是你想本身控制mapping,你也可使用create回調。使用回調可讓你本身控制mapping。
舉例,你有一個像這樣的JavaScript對象:
var data = {
name: 'Graham',
children: [
{ id: 1, name: 'Lisa' }
]
}
若是你想本身map children 數組,你能夠這樣聲明:
var mapping = {
'children': {
create: function (options) {
return new myChildModel(options.data);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
支持create回調的options參數是一個JavaScript對象,包含以下:
固然,在內部的create回調裏,你也能夠再次調用ko.mapping.fromJS。一個例子就是:若是你想讓初始的JavaScript對象帶有額外的依賴屬性dependent observables:
var myChildModel = function (data) {
ko.mapping.fromJS(data, {}, this);
this.nameLength = ko.dependentObservable(function () {
return this.name().length;
}, this);
}
用法3:用update自定義對象的updating
你也可使用update 回調來自定義一個對象如何更新。它接受一個須要替代的對象以及和create 回調同樣的options參數,你應該return更新後的值。
update 回調使用的options參數是一個JavaScript對象,包含以下內容:
例子,在數據顯示以前,在新數據後面附加額外的字符串:
var data = {
name: 'Graham',
}
var mapping = {
'name': {
update: function(options) {
return options.data + 'foo!';
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
alert(viewModel.name());
alert的結果是:Grahamfoo!。
用法4:使用ignore忽略不須要map的屬性
若是在map的時候,你想忽略一些屬性,你可使用ignore累聲明須要忽略的屬性名稱集合:
var mapping = {
'ignore': ["propertyToIgnore", "alsoIgnoreThis"]
}
var viewModel = ko.mapping.fromJS(data, mapping);
你聲明的忽略數組被編譯到默認的ignore數組裏。你能夠像下面代碼同樣來維護它:
var oldOptions = ko.mapping.defaultOptions().ignore;
ko.mapping.defaultOptions().ignore = ["alwaysIgnoreThis"];
用法5:使用include聲明須要map的屬性
默認狀況下,當map你的view model回到JS對象是時候,只map原始view model裏擁有的屬性(除了例外的_destroy屬性),不過,你可使用include參數來定製:
var mapping = {
'include': ["propertyToInclude", "alsoIncludeThis"]
}
var viewModel = ko.mapping.fromJS(data, mapping);
你聲明的include數組被編譯到默認的include數組裏,默認只有_destroy。 你能夠像這樣來維護:
var oldOptions = ko.mapping.defaultOptions().include;
ko.mapping.defaultOptions().include = ["alwaysIncludeThis"];
用法6:使用copy來複制屬性
默認狀況下,map的時候是把全部的值都轉換成observable的,若是你只是想copy屬性值而不是替換成observable的,你能夠將屬性名稱添加到copy數組:
var mapping = {
'copy': ["propertyToCopy"]
}
var viewModel = ko.mapping.fromJS(data, mapping);
你聲明的copy數組被編譯到默認的copy數組裏,默認值是空。你能夠像這樣來維護:
var oldOptions = ko.mapping.defaultOptions().copy;
ko.mapping.defaultOptions().copy = ["alwaysCopyThis"];
用法7:Specifying the update target
在上面的例子,若是你想再一個class內map,你可使用第三個參數做爲操做的目標,例如:
ko.mapping.fromJS(data, {}, someObject); // overwrites properties on someObject
因此,若是你想map一個JavaScript對象到this上,你能夠這樣聲明:
ko.mapping.fromJS(data, {}, this);
從多數據源map
你能夠經過屢次使用ko.mapping.fromJS 來將多個JS對象的數據源map到一塊兒,例如:
var viewModel = ko.mapping.fromJS(alice, aliceMappingOptions);
ko.mapping.fromJS(bob, bobMappingOptions, viewModel);
你聲明的mapping選項option在每次調用的時候都會合並。
Map之後的observable數組
map插件map之後生產的observable數組,帶有幾個額外的函數來處理帶有keys的mapping:
它們是和ko.observableArray裏的函數等價的,不一樣是他們經過key來處理對象。例如:
var obj = [
{ id: 1 },
{ id: 2 }
]
var result = ko.mapping.fromJS(obj, {
key: function (item) {
return ko.utils.unwrapObservable(item.id);
}
});
result.mappedRemove({ id: 2 });
map過的observable數組,除了上面的函數還支持一個mappedCreate函數:
var newItem = result.mappedCreate({ id: 3 });
首先會檢查key(id=3)在數組裏是否存在(若是存在則拋出異常),而後,若是有create和 update回調的話會調用他們,最後建立一個新對象,並將新對象添加到數組而後返回該新對象。
下載
Version 2.0 (最小版本8.6kb)