• KO的反射


    最近终于在实际项目中使用了 knockout.js,MVVM 模式的双向绑定和通知功能让我兴奋,感觉很不错,这个感觉就像当初从原生的 js 转向 jquery 一样,它开辟了一个新的编写模式,从更高的层次上满足了一些前端应用的需求。jquery 和 knockout 都是我觉得很 nice 的东西,对提高生产力有着很不错的促进作用,它们是前端完美的搭配。

    jquery着重解决了同documet交互的问题,knockout着重解决了同business交互的问题

    knockout.js 在文档方面写的还是比较详尽的,还有Live ExamplesTutorial,让你能很快的上手,不得不再称赞一下。它原生提供了很多的功能,可以满足绝大所数的开发需求了,唯独一点让我觉得有点遗憾,那就是 ko 的初始化,我最初的做法是先输出 json 给 ko 进行初始化,然后让 ko 更新到 UI,这样本身没什么问题,这也是教科书的做法。

    但是倘若目标是一些零散的数据那就变得很繁琐了,我理想的方式还是直接把零散的数据绑定到UI上,然后让 UI 数据反射到 ko,这样就完美了,这样做还有一个好处:UI 可以及时显示该有的状态,因为通过 json 给 ko 初始化的方式总是会让我看到 ko 初始化后更新 UI 那一霎那的值变化,有点代码洁癖的我可受不了。

    还好 ko 提供了自定义的扩展功能,使得应用变得无限的宽广了,我的想法也变得有思路来实现了,那就是做一个 reflect binding。

    ko.bindingHandlers.reflect = {
        init: function (element, valueAccessor, allValueAccessor, viewModel) {
            // observable value
            var observableValue = valueAccessor(), allAccessor = allValueAccessor();
            if (observableValue === false) { return; }
            // reflect select
            if (element.tagName === 'SELECT') {
                var optionsAccessor = allAccessor['options'],
                    txtKey = allAccessor['optionsText'],
                    valKey = allAccessor['optionsValue'],
                    caption = allAccessor['optionsCaption'];
                var existingOptions = optionsAccessor();
                if (!existingOptions || !existingOptions.length) {
                    var options = [];
                    if (caption) {
                        var c = {};
                        c[txtKey] = caption;
                        c[valKey] = '';
                        options.push(c);
                    }
                    $(element).find('option').each(function () {
                        var item = {};
                        item[txtKey] = $(this).text();
                        item[valKey] = $(this).val();
                        options.push(item);
                    });
                    optionsAccessor(options);
                }
                observableValue($(element).val());
            }
            // reflect textarea
            if (element.tagName === 'TEXTAREA') {
                observableValue($(element).val());
            }
            // reflect input
            if (element.tagName === 'INPUT') {
                var t = element.type.toLowerCase();
                if (t === 'text' || t === 'hidden') {
                    observableValue($(element).val());
                }
                if (t === 'radio' || t === 'checkbox') {
                    var target = element;
                    if (element.name) {
                        var find = $('input[name="' + element.name + '"]:checked');
                        if (find.length > 0) { target = find.get(0); }
                    }
                    var elval = $(target).val();
                    if (target.checked && elval) {
                        observableValue(elval);
                    } else {
                        observableValue(target.checked);
                    }
                }
            }
        }
    };
    <select data-bind="reflect:Passenger, value:Passenger, options:PassengerOptions, optionsText:'tint', optionsValue:'vint'">
        <option value="1">1 person</option>
        <option value="2">2 persons</option>
        <option value="3">3 persons</option>
    </select>
    <input type="text" data-bind="reflect:Destination, value: Destination" value="XMN" />
    function modelClass() {
        this.Passenger = ko.observable();
        this.PassengerOptions = ko.observableArray([]);
        this.Destination = ko.observable();
    }
    ko.applyBindings(new modelClass());

    使用时只需确保 reflect binding 放在 data-bind 第一位即可,这个 reflect binding 是对表单元素的反射绑定,可以按照这个原理在任意 html 元素上反射自己所需要的值。

    浏览器没那么聪明!
  • 相关阅读:
    构建之法阅读笔记01
    学习进度13
    学习进度12
    个人冲刺十
    个人冲刺九
    个人冲刺八
    学习进度11
    个人冲刺七
    个人冲刺六
    [HDU 1232 ]畅通工程
  • 原文地址:https://www.cnblogs.com/rulee/p/2644241.html
Copyright © 2020-2023  润新知