Vue源码解析--实现一个watcher

2021/5/5 20:55:20

本文主要是介绍Vue源码解析--实现一个watcher,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

实现Watcher

 我们前面讲过,Observe()函数实现data对象的属性劫持,并在属性值改变时触发订阅器的notify()通知订阅者Watcher,订阅者就会调用自身的update方法实现视图更新。

Compile()函数负责解析模板,初始化页面,并且为每个data属性新增一个监听数据的订阅者(new Watcher)。

Watcher订阅者作为Observer和Compile之间通信的桥梁,所以我们可以大致知道Watcher的作用是什么。

主要做的事情是:

  • 在自身实例化时往订阅器(dep)里面添加自己。
  • 自身必须有一个update()方法 。
  • 待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调。

 先给出全部代码,再分析具体的功能。

//Watcher
function Watcher(vm, exp, cb) {
    this.vm = vm;
    this.cb = cb;
    this.exp = exp;
    this.value = this.get();//初始化时将自己添加进订阅器
};

Watcher.prototype = {
    update: function(){
        this.run();
    },
    run: function(){
        const value = this.vm[this.exp];
        //console.log('me:'+value);
        if (value != this.value){
            this.value = value;
            this.cb.call(this.vm,value);
        }
    },
    get: function() { 
        Dep.target = this;  // 缓存自己
        var value = this.vm[this.exp]  // 访问自己,执行defineProperty里的get函数         
        Dep.target = null;  // 释放自己
        return value;
    }
}

//这里列出Observe和Dep,方便理解
Observe.prototype = {
    defineReactive: function(data,key,value){
        let dep = new Dep();
        Object.defineProperty(data,key,{
            enumerable: true,//可枚举
            configurable: false,//不能再define
            get: function(){
                console.log('你访问了' + key);
                //说明这是实例化Watcher时引起的,则添加进订阅器
                if (Dep.target){
                    //console.log('访问了Dep.target');
                    dep.addSub(Dep.target);
                }
                return value;
            },
        })
    }
}

Dep.prototype = {
    addSub: function(sub){this.subs.push(sub);
    },
}

 

我们知道在Observe()函数执行时,我们为每个属性都添加了一个订阅器dep,而这个dep被闭包在属性的get/set函数内。所以,我们可以在实例化Watcher时调用this.get()函数访问data.name属性,这会触发defineProperty()函数内的get函数,get方法执行的时候,就会在属性的订阅器dep添加当前watcher实例,从而在属性值有变化的时候,watcher实例就能收到更新通知。

那么Watcher()函数中的get()函数内Dep.taeger = this又有什么特殊的含义呢?我们希望的是在实例化Watcher时将相应的Watcher实例添加一次进dep订阅器即可,而不希望在以后每次访问data.name属性时都加入一次dep订阅器。所以我们在实例化执行this.get()函数时用Dep.target = this来标识当前Watcher实例,当添加进dep订阅器后设置Dep.target=null。



这篇关于Vue源码解析--实现一个watcher的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程