简单了解Vue2.0+的数据双向绑定

简单了解Vue2.0+的数据双向绑定

首先,我们提到MVVM双向数据绑定时,想到的先是:数据改变导致视图改变,视图改变同时数据发生改变。然后,我们紧接着就能说出Vue2的数据双向绑定是通过Object.defineProperty()方法对data中的数据进行数据劫持,转化为getter/setter,当数据变化时通知视图更新。下面我们来一步步的实现一下这个绑定过程。

回顾一下Object.defineProperty()

直接先上一个例子,了解一下Object.defineProperty()可以做些什么。

		let testName = "李四"
        let person = {
            name: testName,
            age: 23
        }

当我们输出person时,我们当然知道结果如下:
在这里插入图片描述

可是,当我们修改testName时,再次输出person时,是不是想当然的以为应该输出修改后的值?我们看一下。
在这里插入图片描述
可是,事实上却不是,我们看到的效果好像只有在初始化的时候对person.name进行了赋值。接下来我们使用Object.defineProperty()来实现一下我们认为的效果。

		let testName = "李四"
        let person = {
            name: testName,
            age: 23
        }
        Object.defineProperty(person, 'name', {
            get: function () {
                console.log("name属性被读取了");
                return testName
            },
            set: function (newVal) {
                console.log("name属性被修改了");
                val = newVal
            }
        })

person.name被访问的时候会调用get方法,被赋值时会调用set方法,我们修改输出一下:
在这里插入图片描述
很明显实现了预期的效果。而在Vue的数据双向绑定时,我们也是通过Object.defineProperty()get/set方法知道什么时候被访问,什么时候被赋值,然后通过发布-订阅的方式完成视图更新。

实现一个数据监听器(Observer)

根据上面的例子,我们首先实现一个数据监听器,用来监听数据的所有属性的变化,如有变化则通知视图更新。

		let person = {
            name: "李四",
            age: 23
        }
        let p = Observer(person)

        function Observer(obj) {
            if (!obj || typeof obj !== 'object') {
                return;
            }
            Object.keys(obj).forEach(key => {
                defineReactive(obj, key, obj[key])
            })
            return obj

        }
        function defineReactive(obj, key, val) {
            Object.defineProperty(obj, key, {
                get() {
                    console.log(`${key}属性被读取了`);
                    return val;
                },
                set(newVal) {
                    val = newVal;
                    console.log(`${key}属性被修改了`);
                }
            })
        }

在这里插入图片描述
到这里,我们这个对象的所有属性都进行了监听。

实现一个订阅器(依赖收集)

上一步,完成了对所有属性的监听,知道数据什么时候发生变化,那我们就可以在数据发生改变的时候通知依赖该数据的视图进行更新,这就是上面提到的发布订阅者模式我们需要实现一个订阅者容器,用来存放所有的订阅者,当数据发生变化时,通知对应的订阅者,执行它的更新函数。

        function defineReactive(obj, key, val) {
            let dep = new Dep()
            Object.defineProperty(obj, key, {
                get() {
                    dep.depend();
                    console.log(`${key}属性被读取了`);
                    return val;
                },
                set(newVal) {
                    val = newVal;
                    console.log(`${key}属性被修改了`);
                    dep.notify()
                }
            })
        }
        class Dep {
            constructor() {
                this.subs = []
            }
            //增加订阅者
            addSub(sub) {
                this.subs.push(sub)
            }
            //判断是否增加订阅者
            depend() {
                if (Dep.target) {
                    this.addSub(Dep.target)
                }
            }
            //通知订阅者更新
            notify() {
                this.subs.forEach(sub => {
                    sub.update()
                })
            }
        }
        Dep.target = null

实现订阅者

	class Watcher {
	    constructor(vm, exp, cb) {
	        this.vm = vm;
	        this.exp = exp;
	        this.cb = cb;
	        this.value = this.get(); // 将自己添加到订阅器的操作
	    }
	    get() {
	        Dep.target = this; // 缓存自己
	        let value = this.vm.data[this.exp] // 强制执行监听器里的get函数
	        Dep.target = null; // 释放自己
	        return value;
	    }
	    update() {
	        let value = this.vm.data[this.exp];
	        let oldVal = this.value;
	        if (value !== oldVal) {
	            this.value = value;
	            this.cb.call(this.vm, value, oldVal);
	        }
	    }
	}

vm是Vue的实例,
exp是node节点的属性值,
cb是更新函数

一个简单的订阅者完成,我们来测试一下:
在这里插入图片描述

但是在Vue2.0+中,当对对象属性进行删除或者新增或者根据索引修改数组内容时,双向绑定和响应式还是有些问题的:

let person = {
	name:"张三",
	age:15,
	hobbies:["抽烟","喝酒","烫头"]
}
delete person.name
person.sex = "男"
person.hobbies[0] = "学习"

但是可以通过Vue提供的API进行操作:Vue.set(),Vue.delete

细节正在补充中。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值