实现的原理

vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据发生变动时发布消息给订阅者,触发相应的监听回调。

具体的步骤

第一步:实现数据监听器observe,对数据进行递归遍历,包括子属性对象的属性,都相应的添加上getter、setter,这样在给某个属性赋值时都会触发setter,就能监听到数据的变化。

第二步:实现解析模板指令compile,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,渲染视图。

第三步:watcher订阅者时observe数据监听器和compile解析模板指令的通信桥梁,主要实现在在自身实例变化时往属性订阅器(dep)里面添加自己,待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调函数。

第四步:MVVM作为数据绑定的入口,整合Observe、Compile和watcher三者,通过Observer来监听自己的model数据的变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

如下图所示:

iosrxswift双向绑定 实现双向绑定_数据


上代码:

<div id="app"></div>
<input type="text" id="input">
// 定义一个空的obj对象
var obj = {};
// 定义一个空数据
var value = "";
// 我们使用Object.defineProperty进行数据劫持,
// 给obj添加一个名叫msg的属性
// 改函数接收三个参数
// 1.第一个参数,是一个对象
// 2.第二个参数,是给该对象上设置的属性名
// 3.第三个参数,是一个配置对象,可以配置该属性的set/get方法
Object.defineProperty(obj, "msg", {
    set: function(newValue) {
        console.log("执行了set函数");
        // 当数据发生变动时,我们重新渲染对应的html
        document.querySelector("#app").innerHTML = newValue;
        value = newValue;
    },
    get: function() {
        console.log("执行了get函数");
        return value;
    }
});
// 监听input事件,当发生变化时
// 重新设置obj的msg属性,触发set函数,则view自动更新
document.querySelector("#input").addEventListener("input", function(e) {
    obj.msg = e.target.value;
});

一旦输入框中的内容发生改变,就会触发oninput事件马上改变data中的内容,一旦data中的name发生改变就会触发set方法将最新的值赋值给v,这样就实现了数据的双向绑定

iosrxswift双向绑定 实现双向绑定_数据_02