Vue2数据双向绑定的原理

一、Vue的双向绑定

双向绑定在于数据变化更新视图,视图变化更新数据,因为视图更新数据可以通过事件监听来控制,着重点就是数据变化如何更新视图。

二、实现过程

监听器observer对数据进行劫持监听,数据对象都会通过Object.defineProperty设置set和get方法。由于data中的某个key在一个视图中可能出现多次,所以订阅者是有多个的,所以需要一个消息订阅器dep来专门收集这些订阅者。当订阅者watcher接收到相应属性的变化(如果属性发生变化,会触发set方法),就会执行对应订阅者的更新函数,从而更新视图。

三、代码实现

1、实现一个Observer,通过递归遍历所有属性,通过Object.defineProperty给所有属性添加set和get方法。

//给对象的所有属性添加set、get方法
function defineReactive(data, key, val) {
    //递归遍历子属性
    observe(val)
    Object.defineProperty(data, key, {
        //可枚举
        enumerable: true,
        //可以被配置
        configurable: true,
        get: function() {
            return val;
        },
        set: function(newval) {
            val = newval;
            console.log("数据发生了变化");
        }
    })
}

function observe(data) {
    //如果不是对象直接返回
    if (!data || typeof data != "object") {
        return;
    }
    Object.keys(data).forEach(function(key) {
        defineReactive(data, key, data[key])
    })
}

2、创建一个可以容纳订阅者的消息订阅器Dep,订阅器Dep主要负责收集订阅者,然后在属性变化的时候执行对应订阅者的更新函数。

//2、给对象的所有属性添加set、get方法
function defineReactive(data, key, val) {
    //递归遍历子属性
    observe(val);
    var dep = new Dep();
    Object.defineProperty(data, key, {
        //可枚举
        enumerable: true,
        //可以被配置
        configurable: true,
        get: function() {
            if (是否需要订阅者) {
                dep.addSub(watcher); //添加一个订阅者
            }
            return val;
        },
        set: function(newval) {
            if (newval === val) {
                return;
            }
            val = newval;
            console.log("数据发生了变化");
            //数据发生变化,通知所有订阅者
            dep.notify();
        }
    })
}
//1、创建数据监听器
function observe(data) {
    //如果不是对象直接返回
    if (!data || typeof data != "object") {
        return;
    }
    Object.keys(data).forEach(function(key) {
        defineReactive(data, key, data[key])
    })
}
//3、创建订阅器Dep
function Dep() {
    this.subs = [];
}
//4、给Dep增加 添加订阅者和通着订阅者更新的方法
Dep.prototype = {
    addSub: function(sub) {
        this.subs.push(sub);
    },
    notify: function() {
        this.subs.forEach((sub) => {
            sub.update();
        })
    }
}

3、实现一个watcher,可以收到属性的变化通知执行相应的函数

    //5、创建订阅者watcher
function watcher(vm, exp, cb) {
    this.cb = cb;
    this.vm = vm;
    this.exp = exp;
    this.value = this.get(); //触发get方法,将自己添加到订阅器
}
watcher.prototype = {
    update: function() {
        this.run();
    },
    run: function() {
        //获取新值
        var value = this.vm.data[this.exp];
        //获取当前值
        var oldVal = this.value;
        if (value != oldVal) {
            this.value = value;
            this.cb.call(this.vm, value, oldVal)
        }
    },
    get: function() {
        Dep.target = this; //缓存自己
        var value = this.vm.data[this.exp]; //强制执行监听器里的get函数
        Dep.target = null; //释放自己
        return value;
    }
}

4、稍微修改Observer的defineReactive方法
在这里插入图片描述
5、将Observer和watcher关联起来

    //6、将Observer和Watcher关联起来
function SelfVue(data, el, exp) {
    this.data = data;
    observe(data);
    el.innerHTML = this.data[exp]; //初始化模板数据的值
    new Watcher(this, exp, function(value) {
        el.innerHTML = value;
    })
    return this;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值