vue响应式小记

看了许多介绍vue原理的文章,抄写下来做个记录,方便后续回顾

VUE的响应式原理是先将vue对象的所有属性遍历一遍,为每个属性都添加gettersetter方法,接着当render function被渲染的时候,因为会读取所需对象的属性,因此会触发getter函数进行【依赖收集】,【依赖收集】的目的是将Watcher对象添加到当前闭包中的订阅者Depsubs中。在修改对象的值时,会触发对应的settersetter通知之前【依赖收集】得到的Dep中的每一个Watcher,告诉它们自己的值改变了,需要重新渲染视图。这时候这些Watcher 就会开始调用update来更新视图。

订阅者 Dep

订阅者 Dep ,它的主要作用是用来存放 Watcher 观察者对象。主要有以下两个功能:

  1. addSub 方法可以在目前的 Dep 对象中增加一个 Watcher 的订阅操作;
  2. notify 方法通知目前 Dep 对象的 subs 中的所有 Watcher 对象触发更新操作。
class Dep {
    constructor () {
        /* 用来存放Watcher对象的数组 */
        this.subs = [];
    }

    /* 在subs中添加一个Watcher对象 */
    addSub (sub) {
        this.subs.push(sub);
    }

    /* 通知所有Watcher对象更新视图 */
    notify () {
        this.subs.forEach((sub) => {
            sub.update();
        })
    }
}

观察者 Watcher

class Watcher {
    constructor () {
        /* 在new一个Watcher对象时将该对象赋值给Dep.target,在get中会用到 */
        Dep.target = this;
    }

    /* 更新视图的方法 */
    update () {
        console.log("视图更新啦~");
    }
}

Dep.target = null;

监听器 Observer

// observe方法遍历并包装对象属性
function observe(target) {
    // 若target是一个对象,则遍历它
    if(target && typeof target === 'object') {
        Object.keys(target).forEach((key)=> {
            // defineReactive方法会给目标属性装上“监听器”
            defineReactive(target, key, target[key])
        })
    }
}

依赖收集

function defineReactive (obj, key, val) {
    /* 一个Dep类对象 */
    const dep = new Dep();
    /* 属性值也可能是object类型,这种情况下需要调用observe进行递归遍历 */
    observe(val);
    
    // 为当前属性安装监听器
    Object.defineProperty(obj, key, {
     	// 可枚举
        enumerable: true,
        // 不可配置
        configurable: true,
        get: function reactiveGetter () {
            /* 将Dep.target(即当前的Watcher对象存入dep的subs中) */
            dep.addSub(Dep.target);
            return val;         
        },
        // 监听器函数
        set: function reactiveSetter (newVal) {
            if (newVal === val) return;
            /* 在set的时候触发dep的notify来通知所有的Watcher对象更新视图 */
            dep.notify();
        }
    });
}

class Vue {
    constructor(options) {
        this._data = options.data;
        observe(this._data);
        /* 新建一个Watcher观察者对象,这时候Dep.target会指向这个Watcher对象 */
        new Watcher();
        /* 在这里模拟render的过程,为了触发test属性的get函数 */
        console.log('render~', this._data.test);
    }
}

简单示例

let vm=new Vue({
	data:{
		test:"origin"
	}
});
vm._data.test="测试更改!";

/* 运行结果
 * render~ origin
 * 视图更新啦~
 * "测试更改!"
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值