KnockoutJS 3.X API 第八章 映射(mapping)插件

Knockout旨在容許您將任意JavaScript對象用做視圖模型。 只要一些視圖模型的屬性是observables,您可使用KO將它們綁定到您的UI,而且UI將在可觀察屬性更改時自動更新。git

大多數應用程序須要從後端服務器獲取數據。 因爲服務器沒有任何可觀察的概念,它只提供一個純JavaScript對象(一般序列化爲JSON)。 映射插件提供了一種簡單的方法來將該簡單的JavaScript對象映射到具備適當的observables的視圖模型中。 這是替代手動編寫本身的JavaScript代碼,根據您從服務器獲取的一些數據構建視圖模型。github

下載映射插件(你須要翻個牆)

 

示例:不帶ko.mapping插件的手動映射

您要顯示當前服務器時間和您的網頁上的用戶數。 您可使用如下視圖模型表示此信息:ajax

var viewModel = {
    serverTime: ko.observable(),
    numUsers: ko.observable()
}

您能夠將此視圖模型綁定到一些HTML元素,以下所示:後端

The time on the server is: <span data-bind='text: serverTime'></span>
and <span data-bind='text: numUsers'></span> user(s) are connected.

因爲視圖模型屬性是可觀察的,KO將在這些屬性更改時自動更新HTML元素。數組

接下來,您要從服務器獲取最新數據。 每5秒您能夠發出一個Ajax請求(例如,使用jQuery的$ .getJSON或$ .ajax函數):服務器

var data = getDataUsingAjax();          // Gets the data from the server

服務器可能返回相似於如下內容的JSON數據:數據結構

{
    serverTime: '2010-01-07',
    numUsers: 3
}

最後,要使用此數據更新視圖模型(不使用映射插件),您應該寫:app

// Every time data is received from the server:
viewModel.serverTime(data.serverTime);
viewModel.numUsers(data.numUsers);

你必須爲你想在頁面上顯示的每一個變量這樣作。 若是您的數據結構變得更加複雜(例如,它們包含子節點或包含數組),則手動處理變得很是麻煩。 映射插件容許您作的是建立從常規JavaScript對象(或JSON結構)到可觀察視圖模型的映射。函數

 

示例:使用ko.mapping

要經過映射插件建立視圖模型,請將上面代碼中的viewModel的建立替換爲ko.mapping.fromJS函數:ui

// Every time data is received from the server:
ko.mapping.fromJS(data, viewModel);

如何映射

  • 對象的全部屬性都將轉換爲observable。 若是更新將更改值,它將更新observable。
  • 數組被轉換爲可觀察數組。 若是更新會更改項目數,則它將執行適當的添加/刪除操做。 它還將嘗試保持與原始JavaScript數組相同的順序。

取消映射

若是要將映射對象轉換回常規JS對象,請使用:

var unmapped = ko.mapping.toJS(viewModel);

這將建立一個未映射的對象,只包含做爲原始JS對象的一部分的映射對象的屬性。 所以,換句話說,您手動添加到視圖模型的任何屬性或函數都將被忽略。 默認狀況下,此規則的惟一例外是_destroy屬性,它也將被映射回來,由於它是Knockout在從ko.observableArray中銷燬項目時可能生成的屬性。 有關如何配置此項的更多詳細信息,請參閱「高級應用」章節。

使用JSON字符串

若是您的Ajax調用返回一個JSON字符串(而且不將其反序列化爲JavaScript對象),那麼您可使用函數ko.mapping.fromJSON來建立和更新視圖模型。 要取消映射,可使用ko.mapping.toJSON。

除了它們使用JSON字符串而不是JS對象的事實,這些函數與它們的JS對象徹底相同。

高級用法

有時,可能有必要對如何執行映射有更多的控制。 這是使用映射選項實現的。 它們能夠在ko.mapping.fromJS調用期間指定。 在後續調用中,您不須要再次指定它們。

在這種狀況下,您可能須要使用這些映射選項。

使用「key」惟一標識對象

假設您有一個相似於如下內容的JavaScript對象:

var data = {
    name: 'Scot',
    children: [
        { id : 1, name : 'Alicw' }
    ]
}

您能夠將此映射到視圖模型沒有任何問題:

var viewModel = ko.mapping.fromJS(data);

如今,假設數據更新爲沒有任何拼寫錯誤:

var data = {
    name: 'Scott',
    children: [
        { id : 1, name : 'Alice' }
    ]
}

這裏發生了兩件事情:name從Scot改成Scott,children[0] .name從Alicw變成了Alice。 您能夠基於此新數據更新viewModel:

ko.mapping.fromJS(data, viewModel);

和名稱會改變,如預期。 可是,在children數組中,子(Alicw)將被徹底刪除,並添加一個新的(Alice)。 這不是徹底你會指望的。 相反,你會但願只有孩子的name屬性從Alicw更新到Alice,而不是整個孩子被替換!

這是由於,默認狀況下,映射插件只是比較數組中的兩個對象。 由於在JavaScript中,對象{id:1,name:'Alicw'}不等於{id:1,name:'Alice'},它認爲整個孩子須要被刪除並被一個新的替換。

要解決這個問題,你能夠指定映射插件應該使用哪一個鍵來肯定對象是新的仍是舊的。 你能夠這樣設置:

var mapping = {
    'children': {
        key: function(data) {
            return ko.utils.unwrapObservable(data.id);
        }
    }
}
var viewModel = ko.mapping.fromJS(data, mapping);

這樣,每次映射插件檢查children數組中的一個項目時,它只會查看id屬性來肯定一個對象是否被徹底替換或只是須要更新。

使用「create」定製對象構造

若是你想本身處理映射的一部分,你也能夠提供一個create回調。 若是這個回調存在,映射插件將容許你本身作這部分的映射。

假設您有一個相似於如下內容的JavaScript對象:

var data = {
    name: 'Graham',
    children: [
        { id : 1, name : 'Lisa' }
    ]
}

若是你想本身映射children數組,你能夠這樣指定:

var mapping = {
    'children': {
        create: function(options) {
            return new myChildModel(options.data);
        }
    }
}
var viewModel = ko.mapping.fromJS(data, mapping);

提供給create回調的options參數是一個JavaScript對象,其中包含:

  • data: 包含此子項的數據的JavaScript對象
  • parent: 此子項所屬的父對象或數組

固然,在建立回調中你能夠作另外一個調用ko.mapping.fromJS若是你願意。 一個典型的用例多是,若是你想用一些額外的計算observables擴充原始的JavaScript對象:

var myChildModel = function(data) {
    ko.mapping.fromJS(data, {}, this);
     
    this.nameLength = ko.computed(function() {
        return this.name().length;
    }, this);
}

使用「update」定製對象更新

您還能夠經過指定更新回調來自定義對象的更新方式。 它將接收它試圖更新的對象和一個與create回調所使用的相同的選項對象。 您應該返回更新的值。

提供給更新回調的options參數是一個JavaScript對象,包含:* data:包含此子節點數據的JavaScript對象* parent:此子節點所屬的父對象或數組* observable:若是屬性是可觀察的 將被設置爲實際可觀察的

下面是一個配置示例,將在更新以前向輸入數據添加一些文本:

var data = {
    name: 'Graham',
}
 
var mapping = {
    'name': {
        update: function(options) {
            return options.data + 'foo!';
        }
    }
}
var viewModel = ko.mapping.fromJS(data, mapping);
alert(viewModel.name());

這將彈窗提示Graham Foo!

使用「ignore」忽略某些屬性

若是你想映射插件忽略你的JS對象的一些屬性(即不映射它們),你能夠指定一個屬性名稱數組來忽略:

var mapping = {
    'ignore': ["propertyToIgnore", "alsoIgnoreThis"]
}
var viewModel = ko.mapping.fromJS(data, mapping);

您在映射選項中指定的忽略數組與默認忽略數組相結合。 你能夠像這樣操做這個默認數組:

var oldOptions = ko.mapping.defaultOptions().ignore;
ko.mapping.defaultOptions().ignore = ["alwaysIgnoreThis"];

使用「include」包括某些屬性

當將視圖模型轉換回JS對象時,默認狀況下,映射插件將僅包含屬於原始視圖模型的屬性,但它也將包括Knockout生成的_destroy屬性,即便它不是原始對象的一部分 。 可是,您能夠選擇自定義此數組:

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"];

使用「copy」複製某些屬性

將視圖模型轉換回JS對象時,默認狀況下,映射插件將根據上述規則建立可觀察項。 若是你想強制映射插件簡單地複製屬性而不是使其可見,添加其名稱到「複製」數組:

var mapping = {
    'copy': ["propertyToCopy"]
}
var viewModel = ko.mapping.fromJS(data, mapping);

您在映射選項中指定的副本數組與默認副本數組相結合,默認狀況下爲空。 你能夠像這樣操做這個默認數組:

var oldOptions = ko.mapping.defaultOptions().copy;
ko.mapping.defaultOptions().copy = ["alwaysCopyThis"];

僅使用「observe」觀察某些屬性

若是你但願映射插件只建立你的JS對象的一些屬性的可觀察和複製,你能夠指定一個屬性名稱數組觀察:

var mapping = {
    'observe': ["propertyToObserve"]
}
var viewModel = ko.mapping.fromJS(data, mapping);

您在映射選項中指定的觀察數組與默認的觀察數組相結合,默認狀況下爲空。 你能夠像這樣操做這個默認數組:

var oldOptions = ko.mapping.defaultOptions().observe;
ko.mapping.defaultOptions().observe = ["onlyObserveThis"];

數組忽略幷包括仍然正常工做。 數組副本可用於複製數組或對象屬性(包括子元素)的效率。 若是在copy或observe中沒有指定數組或對象屬性,那麼它將被遞歸映射:

var data = {
    a: "a",
    b: [{ b1: "v1" }, { b2: "v2" }] 
};
 
var result = ko.mapping.fromJS(data, { observe: "a" });
var result2 = ko.mapping.fromJS(data, { observe: "a", copy: "b" }); //will be faster to map.

結果和結果2將是:

{
    a: observable("a"),
    b: [{ b1: "v1" }, { b2: "v2" }] 
}

複製和觀察能夠衝突:

var data = {
    a: "a",
    b: [{ b1: "v1" }, { b2: "v2" }] 
};
var result = ko.mapping.fromJS(data, { observe: "b[0].b1"});
var result2 = ko.mapping.fromJS(data, { observe: "b[0].b1", copy: "b" });

結果將是:

{
    a: "a",
    b: [{ b1: observable("v1") }, { b2: "v2" }] 
}

結果2將是:

{
    a: "a",
    b: [{ b1: "v1" }, { b2: "v2" }] 
}

指定更新目標

若是,像在上面的例子中,你正在一個類中執行映射,你但願有它做爲你的映射操做的目標。 ko.mapping.fromJS的第三個參數指示目標。 例如,

ko.mapping.fromJS(data, {}, someObject); // overwrites properties on someObject

因此,若是你想映射一個JavaScript對象到這裏,你能夠傳遞這個做爲第三個參數:

ko.mapping.fromJS(data, {}, this);

從多個來源映射

您能夠經過應用多個ko.mapping.fromJS調用在一個視圖模型中組合多個JS對象,例如:

var viewModel = ko.mapping.fromJS(alice, aliceMappingOptions);
ko.mapping.fromJS(bob, bobMappingOptions, viewModel);

在每一個調用中指定的映射選項將被合併。

映射監控屬性數組

由映射插件生成的可觀察數組經過一些能夠利用鍵映射的函數來擴充:

  • mappedRemove
  • mappedRemoveAll
  • mappedDestroy
  • mappedDestroyAll
  • mappedIndexOf

它們在功能上等同於常規的ko.observableArray函數,可是能夠基於對象的鍵來作事情。 例如:

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 });

映射的observablearray還公開了一個映射的Create函數:

var newItem = result.mappedCreate({ id : 3 });

它將首先檢查鍵是否已經存在,若是是,將拋出異常。 接下來,它將調用create和update回調(若是有的話)來建立新對象。 最後,它將把這個對象添加到數組並返回它。

KnockoutJS 3.X 結語

至此,全部KnockoutJS 3.X的API文檔撰寫完畢,但願這個完整的KnockoutJS中文文檔能對你有所幫助,感謝你的閱讀。若是你以爲不錯,請點一波推薦,關注。若是你以爲文中有那些不妥,歡迎批評指正。

感謝您的閱讀。

轉載請註明出處:http://www.cnblogs.com/smallprogram/ 

再次感謝

相關文章
相關標籤/搜索