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 函数。一旦数据变动,就层层执行回调函数。
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 均不支持。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: 交换友情链接时应该注意什么