vue源码分析之实现observer和watcher(二)

Vue干货 小白 暂无评论

实现一个watcher



v.$watch("a",()=>console.log("哈哈,$watch成功"))

export default class Watcher {
 constructor(vm, expOrFn, cb) {
   this.cb = cb
   this.vm = vm
   //此处简化.要区分fuction还是expression,只考虑最简单的expression
   this.expOrFn = expOrFn
   this.value = this.get()
 }
 update(){
   this.run()
 }
 run(){
   const  value = this.get()
   if(value !==this.value){
     this.value = value
     this.cb.call(this.vm)
   }
 }
 get(){
   //此处简化。。要区分fuction还是expression
   const value = this.vm._data[this.expOrFn]
   return value
 }
}

那么问题来了,我们怎样将通过addSub(),将Watcher加进去呢。

我们发现var dep = new Dep() 处于闭包当中,我们又发现Watcher的构造函数里会调用this.get。所以,我们可以在上面动动手脚,修改一下Object.defineProperty的get要调用的函数,判断是不是Watcher的构造函数调用,如果是,说明他就是这个属性的订阅者。果断将他addSub()中去,那问题来了,我怎样判断他是Watcher的this.get调用的,而不是我们普通调用的呢。对,在Dep定义一个全局唯一的变量,跟着思路我们写一下



export default class Watcher {
 ....省略未改动代码....
 get(){
   Dep.target = this
   //此处简化。。要区分fuction还是expression
   const value = this.vm._data[this.expOrFn]
   Dep.target = null
   return value
 }
}

这样的话,我们只需要在Object.defineProperty的get要调用的函数里,判断有没有值,就知道到底是Watcher 在get,还是我们自己在查看赋值,如果是Watcher的话就addSub(),代码补充一下



export function defineReactive (obj, key, val) {
 var dep = new Dep()
 var childOb = observe(val)

 Object.defineProperty(obj, key, {
   enumerable: true,
   configurable: true,
   get: ()=>{
     // 说明这是watch 引起的
     if(Dep.target){
       dep.addSub(Dep.target)
     }
     return val
   },
   set:newVal=> {
     var value =  val
     if (newVal === value) {
       return
     }
     val = newVal
     childOb = observe(newVal)
     dep.notify()
   }
 })
}

最后不要忘记,在DEP.js中加上这么一句

Dep.target = null

4.实现一个vue



import Watcher from '../watcher'
import {observe} from "../observer"

export default class Vue {
 constructor (options={}) {
   //这里简化了。。其实要merge
   this.$options=options
   //这里简化了。。其实要区分的
   let data = this._data=this.$options.data
   Object.keys(data).forEach(key=>this._proxy(key))
   observe(data,this)
 }

 $watch(expOrFn, cb, options){
   new Watcher(this, expOrFn, cb)
 }

 _proxy(key) {
   var self = this
   Object.defineProperty(self, key, {
     configurable: true,
     enumerable: true,
     get: function proxyGetter () {
       return self._data[key]
     },
     set: function proxySetter (val) {
       self._data[key] = val
     }
   })
 }
}


转载请注明: Vue教程中文网 - 打造国内领先的vue学习网站-vue视频,vue教程,vue学习,vue培训 » vue源码分析之实现observer和watcher(二)

喜欢 ()or分享