以前有了解過knockout,學習過綁定語法,結合幫助文檔,作個Demo倒也不成問題,可是部分地方很不爽,不知道是個人用法不對,仍是功力不夠。javascript
好比說,標籤裏定義的data-bind屬性名,必須在調用 ko.applyBindings(viewModel) 前必須定義。而結合具體的示例來看,html有以下代碼:html
用戶名:<label data-bind="text:userName"></label> 姓名:<label data-bind="text:realName"></label> 畢業院校:<select data-bind=" options:school, optionsText:'schoolName', optionsValue:'schoolID', value:bySchool, optionsCaption:'請選擇' "></select>
初步寫法則是:java
var viewModel =
{
userName: ko.observable(), realName: ko.observable(), value: ko.observable(), options: ko.observableArray() } ko.applyBindings(viewModel); //後面ajax操做來修改viewModel setTimeout(function () { //加載可選擇院校 var school = [{ schoolID: 1, schoolName: "清華大學" }, { schoolID: 2, schoolName: "北京大學" }, { schoolID: 3, schoolName: "復旦大學" } ]; viewModel.school(school); //加載用戶信息 var user = { userName: 'codealone', realName: '衝動', bySchool: 1 }; viewModel.userName(user.userName); viewModel.realName(user.realName); viewModel.bySchool(user.bySchool); });
寫到這,有人可能要跟我說,mapping 插件能夠解決這個問題。相關代碼以下:ajax
The time on the server is: <span data-bind='text: serverTime'></span> and <span data-bind='text: numUsers'></span>user(s) are connected. <script type="text/javascript"> var data = { serverTime: '2010-01-07', numUsers: 3 }; var viewModel = {}; viewModel = ko.mapping.fromJS(data); ko.applyBindings(viewModel); </script>
這樣的確是能夠解決,但是問題是,個人數據是ajax加載的呀。那麼要先定義屬性,因而修改後的代碼則是:數組
The time on the server is: <span data-bind='text: serverTime'></span> and <span data-bind='text: numUsers'></span>user(s) are connected. <script type="text/javascript"> var viewModel = {}; viewModel.serverTime = ko.observable(); viewModel.numUsers = ko.observable(); ko.applyBindings(viewModel); setTimeout(function () { //模擬ajax取數據 var data = { serverTime: '2010-01-07', numUsers: 3 }; ko.mapping.fromJS(data, viewModel); document.title = "方法已執行"; }, 1000); </script>
看起來很好,不過直到數據並無更新。只有先在初始化以前mapping一次,後面才能夠直接更改。數據結構
The time on the server is: <span data-bind='text: serverTime'></span> and <span data-bind='text: numUsers'></span>user(s) are connected. <script type="text/javascript"> var data = { serverTime: '', numUsers: '' }; var viewModel = ko.mapping.fromJS(data); ko.applyBindings(viewModel); setTimeout(function () { //模擬ajax取數據 var data = { serverTime: '2010-01-07', numUsers: 3 }; ko.mapping.fromJS(data, viewModel); document.title = "方法已執行"; }, 1000); </script>
這樣的話,就沒有問題的,可是這種寫法讓我很鬱悶的是,難不成,我要把事先用到的數據結構所有先定義出來,而後mapping。app
後來以爲ko在初始化的時候,去檢測每一個須要綁定的屬性,是否已經定義,若是未定義,則拋出異常,這個邏輯讓我很不爽,可是不在初始化的時候定義,ko 根本就不知道須要監控哪些屬性的變化,而這些屬性究竟是對象,仍是數組。想到這裏,以爲初始化的定義難以免,就想了個方法,批量註冊初始化觀察對家和批量註冊。實現方式很簡單,看源碼就能夠得知。這裏貼一下調用方式,第一行代碼中的data參數是爲了將批量註冊的屬性名存下來,便於後面直接取出這幾個屬性的值。ecmascript
ko.mapper.observable(viewModel, ['userName', 'realName', 'bySchool'], 'data');
ko.mapper.observableArray(viewModel, ['school']);
以上操做則是完成了初始化,那麼後面的賦值如何批量來進行呢,調用方式以下:ide
//加載可選擇院校 var school = [{ schoolID: 1, schoolName: "清華大學" }, { schoolID: 2, schoolName: "北京大學" }, { schoolID: 3, schoolName: "復旦大學" } ]; ko.mapper.extend(viewModel, { school: school }); //加載用戶信息 var users = { userName: 'codealone', realName: '衝動', bySchool: 1 }; ko.mapper.extend(viewModel, users);
第一個extend,最終執行了 viewModel.school(school);學習
第二個extend,最終執行了viewModel.userName(users.UserName),viewModel.realName(users.realName);等。
這樣算是完成了一種mapping。
再說說說剛剛的data參數問題,data參數是爲了將屬性保存下來,便於後面取出這些屬性的值。Ko的取值是這樣的,拿上面的viewModel來講,定義了userName,realName,bySchool,那麼取值方式則是viewModel.userName(),viewModel.realName(),viewModel.bySchool() ...
//讀取頁面上的用戶信息 var userInfo = ko.mapper.getValue(viewModel, 'data'); var userInfo2 = ko.mapper.getValue(viewModel, ['userName', 'realName', 'bySchool']);
這樣獲得的數據則爲:
{
userName:'xxxx',
realName:'xxxxxx',
bySchool:1
}
完整頁面代碼以下:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="../knockout-3.0.0.debug.js"></script> <script src="../knockout.mapper.js"></script> </head> <body> 用戶名:<label data-bind="text:userName"></label> 姓名:<label data-bind="text:realName"></label> 畢業院校:<select data-bind=" options:school, optionsText:'schoolName', optionsValue:'schoolID', value:bySchool, optionsCaption:'請選擇' "></select> </body> </html> <script type="text/ecmascript"> //半自動Mapping var viewModel = {}; ko.mapper.observable(viewModel, ['userName', 'realName', 'bySchool'], 'data'); ko.mapper.observableArray(viewModel, ['school']); ko.applyBindings(viewModel); //全部的數據都是基於ajax讀取的,這裏使用setTimeout進行模擬 setTimeout(function () { //加載可選擇院校 var school = [{ schoolID: 1, schoolName: "清華大學" }, { schoolID: 2, schoolName: "北京大學" }, { schoolID: 3, schoolName: "復旦大學" } ]; ko.mapper.extend(viewModel, { school: school }); //加載用戶信息 var users = { userName: 'codealone', realName: '衝動', bySchool: 1 }; ko.mapper.extend(viewModel, users); //讀取頁面上的用戶信息 var userInfo = ko.mapper.getValue(viewModel, 'data'); var userInfo2 = ko.mapper.getValue(viewModel, ['userName', 'realName', 'bySchool']); }, 1000); </script>
但願能對於ajax加載的數據結構有更好的解決方案。