iuap-design / blog

📖 用友网络大前端技术团队博客

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

iuap design 源码分析系列-双MVVM模型

bluemind7788 opened this issue · comments

分析1 何谓双MVVM

现在已经有很多流行的MVVM框架,如knockout、vue、angular、avalon等,它们都实现了普通的html元素与简单数据(包括基本数据类型和数组)的双向绑定。但是在View层,除了普通的html元素,还有很多js插件,它们是在js代码中通过拼接html的方式渲染出来的前端展示,如很多的jquery插件;在Model层,简单的数据在一些场景下会有些力不从心,如knockout的数组,改变数组的一行中某列的值,View层并不能更新;列的元信息如字段名、校验规则等并不能在数组结构中表示;数组数据的选中行等统计信息,只能在数组外添加计算属性实现。
双MVVM除了实现普通html元素与简单数据绑定外,还实现了普通html元素与复杂数据、jsView插件与简单数据、jsView插件与复杂数据的绑定。

分析2 双MVVM的实现原理

普通html与简单数据、复杂数据的绑定通过knockout就可以搞定,这是我们的第一种绑定方式。
jsView插件与简单数据、复杂数据的绑定是需要针对每一个jsView插件加入一个中介者,这个中介者实现了数据的监听和控件的监听,当数据发生变化时,中介者会去调用jsView插件提供的api去更新view,当控件发生变化时,会调用复杂数据的api更新数据,这是我们的第二种绑定的实现的基本原理。
两种绑定方式的区别绑定view的粒度不同,一个是html元素级别,一个控件级别。在iuap design中,主要是实现了第二种绑定方式。

分析3 举例说明第二种绑定方式

这种绑定方式的代码在src/model/comp-adp目录下,我们以checkbox.js来分析。先看看简化版的代码

u.CheckboxAdapter = u.BaseAdapter.extend({
    init: function (options) {
        var self = this;
        // 初始化控件
        this.comp = new u.Checkbox(this.element);
        this.element['u.Checkbox'] = this.comp; 
        // 监听控件的变化
        this.comp.on('change', function(){
            var modelValue = self.dataModel.getValue(self.field);
            modelValue = modelValue ? modelValue : '';

            if (self.comp._inputElement.checked) {
                self.dataModel.setValue(self.field, self.checkedValue);
            }else{
                self.dataModel.setValue(self.field, self.unCheckedValue)
            }
        });

        if(this.dataModel){
            // 监听datatable的变化
            this.dataModel.ref(this.field).subscribe(function(value) {
                self.modelValueChange(value)
            })
        }
    },
    modelValueChange: function (val) {
        var self = this;
        if (this.comp._inputElement.checked != (val === this.checkedValue)){
            this.comp.toggle();
        }
    }
})

可以看到通过new u.Checkbox(this.element)进行了控件的初始化;this.comp.on('change', function(){...})实现了控件的监听,监听的回调方法中通过self.dataModel.setValue(self.field, self.checkedValue)进行了复杂数据datatable的改变; this.dataModel.ref(this.field).subscribe(function(value) {
self.modelValueChange(value)
})实现了复杂数据的监听,在监听函数modelValueChange中通过this.comp.toggle()`对控件进行了更新。

未完待续