knockout 表单绑定 要怎么Mapping才好_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > knockout 表单绑定 要怎么Mapping才好

knockout 表单绑定 要怎么Mapping才好

 2013/12/15 15:09:05  冲动  博客园  我要评论(0)
  • 摘要:问题之前有了解过knockout,学习过绑定语法,结合帮助文档,做个Demo倒也不成问题,但是部分地方很不爽,不知道是我的用法不对,还是功力不够。比如说,标签里定义的data-bind属性名,必须在调用ko.applyBindings(viewModel)前必须定义。而结合具体的示例来看,html有如下代码:用户名:<labeldata-bind="text:userName"></label>姓名:<labeldata-bind="text
  • 标签:Map 表单 APP

问题

  之前有了解过knockout,学习过绑定语法,结合帮助文档,做个Demo倒也不成问题,但是部分地方很不爽,不知道是我的用法不对,还是功力不够。

  比如说,标签里定义的data-bind属性名,必须在调用 ko.applyBindings(viewModel) 前必须定义。而结合具体的示例来看,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>

  初步写法则是:

        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插件

  写到这,有人可能要跟我说,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: '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。

我的半自动Mapping

  后来觉得ko在初始化的时候,去检测每个需要绑定的属性,是否已经定义,如果未定义,则抛出异常,这个逻辑让我很不爽,但是不在初始化的时候定义,ko 根本就不知道需要监控哪些属性的变化,而这些属性到底是对象,还是数组。想到这里,觉得初始化的定义难以避免,就想了个方法,批量注册初始化观察对家和批量注册。实现方式很简单,看源码就可以得知。这里贴一下调用方式,第一行代码中的data参数是为了将批量注册的属性名存下来,便于后面直接取出这几个属性的值。

    ko.mapper.observable(viewModel, ['userName', 'realName', 'bySchool'], 'data');
    ko.mapper.observableArray(viewModel, ['school']);

  以上操作则是完成了初始化,那么后面的赋值如何批量来进行呢,调用方式如下:

        //加载可选择院校
        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

  }

完整示例

  完整页面代码如下:

class="code_img_closed" src="/Upload/Images/2013121515/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('e2e97048-3762-4787-b9f2-f78d5f0bbe83',event)" src="/Upload/Images/2013121515/2B1B950FA3DF188F.gif" alt="" />
<!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>
完整的半自动Mapping页面

  测试代码下载

 

  希望能对于ajax加载的数据结构有更好的解决方案。

发表评论
用户名: 匿名