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 元素上反射自己所需要的值。

 

你可能感兴趣的:(反射)