以前有了解过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加载的数据结构有更好的解决方案。