欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue.js 中的 $watch使用方法

程序员文章站 2022-06-14 13:46:03
这两天学习了vue.js 中的 $watch这个地方知识点挺多的,而且很重要,所以,今天添加一点小笔记。 observer, watcher, vm 可谓 v...

这两天学习了vue.js 中的 $watch这个地方知识点挺多的,而且很重要,所以,今天添加一点小笔记。

Vue.js 中的 $watch使用方法

observer, watcher, vm 可谓 vue 中比较重要的部分,检测数据变动后视图更新的重要环节。下面我们来看看 如何实现一个简单的 $watch 功能,当然vue 中使用了很多优化手段,在本文中暂不一一讨论。

例子:

// 创建 vm
let vm = new vue({
 data: 'a'
})

// 键路径
vm.$watch('a.b.c', function () {
 // 做点什么
})

先阐明在这个 demo 以及vue 中,它们的关系:

vm 调用 $watch 后,首先调用 observe 函数 创建 observer 实例观察数据,observer 又创建 dep , dep 用来维护订阅者。然后创建 watcher 实例提供 update 函数。一旦数据变动,就层层执行回调函数。

Vue.js 中的 $watch使用方法

observer和observe

递归调用 observe 函数创建 observer。在创建 observer 的过程中,使用 object.defineproperty() 函数为其添加 get set 函数, 并创建 dep 实例。

export function observe (val) {
 if (!val || typeof val !== 'object') {
  return
 }
 return new observer(val)
}
function definereactive (obj, key, val) {
 var dep = new dep()

 var property = object.getownpropertydescriptor(obj, key)
 // 是否允许修改
 if (property && property.configurable === false) {
  return
 }

 // 获取定义好的 get set 函数
 var getter = property && property.get
 var setter = property && property.set

 var childob = observe(val)
 object.defineproperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: () => {
   var value = getter ? getter.call(obj) : val
   // 说明是 watcher 初始化时获取的, 就添加订阅者
   if (dep.target) {
    dep.depend()
    if (childob) {
     childob.dep.depend()
    }
    // if isarray do some....
   }
   return value
  },
  set: (newval) => {
   var value = getter ? getter.call(obj) : val
   if (value === newval) {
    return
   }
   if (setter) {
    setter.call(obj, newval)
   } else {
    val = newval
   }
   childob = observe(newval)
   dep.notify()
  }
 })
}

你可能会疑问 dep.target 是个什么鬼?????

答案是:watcher, 我们接下来看

dep

export default function dep () {
 this.subs = []
}

// 就是你!!~
dep.target = null 

// 添加订阅者
dep.prototype.addsub = function (sub) {
 this.subs.push(sub)
}

// 添加依赖
dep.prototype.depend = function () {
 dep.target.adddep(this)
}

// 通知订阅者:要更新啦~
dep.prototype.notify = function () {
 this.subs.foreach(sub => sub.update())
}

watcher

为了给每个数据添加订阅者,我们想到的办法是在数据的 get 函数中, 但是 get 函数会调用很多次呀~。。。 肿么办?那就给 dep 添加个参数 target

export default function watcher (vm, exporfn, cb) {
 this.cb = cb
 this.vm = vm
 this.exporfn = exporfn
 this.value = this.get()
}

watcher.prototype.get = function () {
 dep.target = this
 const value = this.vm._data[this.exporfn]
 // 此时 target 有值,此时执行到了上面的 definereactive 函数中 get 函数。就添加订阅者
 dep.target = null
 // 为了不重复添加 就设置为 null
 return value
}

vue instance

在 vue instance 做得最多的事情就是初始化 state, 添加函数等等。

// vue 实例
export default function vue(options) {
 this.$options = options
 this._initstate()
}

// 初始化state
vue.prototype._initstate = function () {
 let data = this._data = this.$options.data
 object.keys(data).foreach(key => this._proxy(key))
 observe(data, this)
}

// $watch 函数,
vue.prototype.$watch = function (exporfn, fn, options) {
 new watcher(this, exporfn, fn)
}

总结

至此,我们已经实现了一个简单的 $watch 函数, object.defineproperty() 函数可谓是举足轻重, 因此不支持该函数的浏览器, vue 均不支持。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。