口才与演讲,彭小枫,密爱 剧情
vm.$watch
用法: vm.$watch( exporfn, callback, [options] ) ,返回值为 unwatch 是一个函数用来取消观察;下面主要理解 options 中的两个参数 deep 和 immediate 以及 unwatch
vue.prototype.$watch = function (exporfn, cb, options) { const vm = this options = options || {} const watcher = new watcher(vm, exporfn, cb, options) if(options.immediate) { cb.call(vm, watcher,.value) } return function unwatchfn() { watcher.teardown() } }
immediate
从上面代码中可以看出当 immediate 为 true 时,就会直接进行执行回调函数
unwatch
实现方式是:
class watcher { constructor (vm, exporfn, cb) { this.vm = vm this.deps = [] this.depids = new set() if(typeof exporfn === 'function') { this.getter = exporfn }else { this.getter = parsepath(exporfn) } this.cb = cb this.value = this.get() } .... adddep (dep) { const id = dep.id //参数dep是dep实例对象 if(!this.depids.has(id)) { //判断是否存在避免重复添加 this.depids.add(id) this.deps.push(dep) dep.addsub(this) //this 是依赖 } } teardown () { let i = this.deps.length while (i--) { this.deps[i].removesub(this) } } } let uid = 0 class dep { constructor () { this.id = uid++ ... } ... depend () { if(window.target) { window.target.adddep(this) //将this即当前dep对象加入到watcher对象上 } } removesub (sub) { const index = this.subs.indexof(sub) if(index > -1) { return this.subs.splice(index, 1) } } }
分析
当执行 teardown() 时需要循环;因为例如 exporfn = function () { return this.name + this.age } ,这时会有两个 dep 分别是 name 与 age 分别都加入了 watcher 依赖( this ),都会加入到 this.deps 中,所以需要循环将含有依赖的 dep 都删除其依赖
deep
需要明白的是
怎么做呢?
class watcher { constructor (vm, exporfn, cb, options) { this.vm = vm this.deps = [] this.depids = new set() if(typeof exporfn === 'function') { this.getter = exporfn }else { this.getter = parsepath(exporfn) } if(options) { //取值 this.deep = !!options.deep }else { this.deep = false } this.cb = cb this.value = this.get() } get () { window.target = this let value = this.getter.call(vm, vm) if(this.deep) { traverse(value) } window.target = undefined return value } ... } const seenobjects = new set() function traverse (val) { _traverse(val, seenobjects) seenobjects.clear() } function _traverse(val, seen) { let i, keys const isa = array.isarray(val) if((!isa && isobject(val)) || object.isfrozen(val)) { //判断val是否是对象或者数组以及是否被冻结 return } if(val._ob_) { const depid = val._ob_.dep.id //可以看前面一篇我们对observer类添加了this.dep = new dep(),所以能访问其dep.id if(seen.has(depid)) { return } seen.add(depid) } if(isa) { i = val.length while (i--) _traverse(val[i], seen) } else { keys = object.keys(val) i = keys.length while (i--) _traverse(val[i], seen) } }
分析
的 dep.depend() ,如果发现 val 为数组,则将依赖加入到 observer 的 dep 中,也就实现了对当前数组的拦截
vm.$set
用法: vm.$set(target, key, value)
作用
vue.prototype.$set = function (target, key, val) { if(array.isarray(target) && isvalidarrayindex(key)) { //是数组并且key有效 target.length = math.max(target.length, key) //处理key > target.length target.splice(key, 1, val) //添加新元素,并输出依赖更新同时新元素也会进行`obsever`处理 return val } if(key in targert && !(key in object.prototype) { //能遍历并且是自身key target[key] = val //触发set,执行依赖更新 return val } const ob = target._ob_ if(target.isvue || (ob && ob.vm.count) { //不是vue实例也不是vue实例的根对象(即不是this.$data跟对象) //触发警告 return } if(!ob) { //只添加 target[key] = val return val } definereactive(ob.value, key, val) //进行响应式处理 ob.dep.notify() //触发依赖更新 returnv val }
vm.$delete
用法: vm.$delete( target, key)
作用
vue.prototype.$delete = function (target, key) { if(array.isarray(target) && isvalidarrayindex(key)) { target.splice(key, 1) return } const ob = target._ob_ if(target.isvue || (ob && ob.vm.count) { //不是vue实例也不是vue实例的根对象(即不是this.$data跟对象) //触发警告 return } if(!hasown(target, key)) { return } delete target[key] if(!ob) { return } ob.dep.notify() }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
VUE+elementui组件在table-cell单元格中绘制微型echarts图
Vue通过getAction的finally来最大程度避免影响主数据呈现问题
vue 路由懒加载中给 Webpack Chunks 命名的方法
网友评论