简单实现vue中的依赖收集与响应的方法
脚本之家 / 编程助手:解决程序员“几乎”所有问题!
脚本之家官方知识库 → 点击立即使用
开始
声明一个对象man,可以视为vue中的data
添加Observer
作用在于将参数对象的属性变为响应式,只要对象的属性被读取或者被修改都能观察到。然后新建一个Observer实例,将man作为参数扔进去。这里的proxyData是将man的属性代理到以man为参数的Observer实例上去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | class Observer { constructor(obj) { this .walk(obj) } walk(obj) { Object.keys(obj).forEach(prop => { this [prop] = obj[prop] this .proxyData(obj, prop) this .defineReactive( this , prop, obj[prop]) }) } proxyData(obj, prop) { let _this = this Object.defineProperty(obj, prop, { get() { return _this[prop] }, set(newVal) { _this[prop] = newVal } }) } defineReactive(obj, prop, val) { Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被读取!`) return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) } }) } } new Observer(man) |
这时打印一下man
现在man的属性都是由Observer实例所对应的属性的getter来返回,只有在查看时会被触发
对man的属性进行修改也会触发实例对应属性的setter
添加Watcher
现在的Watcher有点像vue中的computed,实际上就是定义一个计算属性,这个计算属性依赖于前面man中的某些属性,由他们计算而得。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Watcher { constructor(obj, prop, computed) { this .getVal(obj, prop, computed) } getVal(obj, prop, computed) { Object.defineProperty(obj, prop, { get() { console.log(`computed属性 - ${prop}被读取!`) return computed() }, set() { console.error( '计算属性不可被修改!' ) } }) } } new Watcher(man, 'strength' , () => { let {height, weight} = man if (height > 160 && weight > 70) return 'strong' return 'weak' }) |
看起来没什么问题,所依赖的属性如果变了,计算属性只要再被查看(get方法)一次就可以更新了。但vue中的视图渲染是实时的,视图层依赖于数据层,数据变化了,视图层也会跟着变化,不需要手动更新。类比到这个例子就是计算属性如何才能在其所依赖的属性发生变化时被通知从而触发应有的事件?
这时我们先给Watcher加多一个callback,用于处理当依赖的数据被修改时,我这个计算属性该怎么响应
比如当依赖被修改时,我们就把这个计算属性的值打印出来
1 2 3 4 5 6 7 8 9 10 11 12 | class Watcher { constructor(obj, prop, computed, callback) { this .getVal(obj, prop, computed, callback) } new Watcher(man, 'strength' , () => { let {height, weight} = man if (height > 160 && weight > 70) return 'strong' return 'weak' }, () => { console.log(`i am so ${man.strength} !`) }) |
一切都准备好了,接下来就是该如何实现?
我们先看下Watcher中getVal这个方法
1 2 3 4 5 6 7 8 9 10 11 | getVal(obj, prop, computed, callback) { Object.defineProperty(obj, prop, { get() { console.log(`computed属性 - ${prop}被读取!`) return computed() }, set() { console.error( '计算属性不可被修改!' ) } }) } |
当我们查看计算属性时,会调用computed这个方法,相当于查看了其所依赖的height和weight属性,而在上面我们已经让man的所有属性都拥有了get方法,即他们被查看时我们是不是可以把callback塞给他们?
这时候我们引进一个桥梁,来连接Watcher和Observer。
添加Dep
Dep的用处在于当某一个属性(以下称‘自己')被依赖了,将依赖自己的粉丝(们)--也就是Watcher(s),收集起来,假如自己发生了变化,能够及时通知粉丝们。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Dep { constructor() { this .deps = [] } getDeps() { if (!Dep.target || this .deps.includes(Dep.target)) return console.log( '依赖添加' , Dep.target) this .deps.push(Dep.target) } notify() { this .deps.forEach(dep => { dep() }) } } |
这里的Dep.target就是前面所说的callback方法了。这时我们改一下Watcher中的getVal
1 2 3 4 5 6 7 8 9 10 11 12 | getVal(obj, prop, computed, callback) { Object.defineProperty(obj, prop, { get() { Dep.target = callback console.log(`computed属性 - ${prop}被读取!`) return computed() }, set() { console.error( '计算属性不可被修改!' ) } }) } |
在计算属性被查看时,将callback赋值给Dep.target,接下来就会调用其所依赖属性的getter,我们只要在getter里把callback给收集起来就行了。接下来修改依赖属性的getter方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | defineReactive(obj, prop, val) { let dep = new Dep() Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被读取!`) dep.getDeps() // 依赖收集 return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) } }) } |
这时watcher的callback都被依赖属性给收集起来了,当依赖属性发生变化时只要去运行这些callback就可以了。接下来就是修改依赖属性的setter方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | defineReactive(obj, prop, val) { let dep = new Dep() Object.defineProperty(obj, prop, { get() { console.log(`${prop} - 被读取!`) dep.getDeps() return val }, set(newVal) { if (newVal == val) return val = newVal console.log(`${prop} - 被修改!`) dep.notify() // 运行所有callback } }) } |
运行看看
我们加多一个Watcher试试
1 2 3 4 5 6 7 | new Watcher(man, 'isGreat' , () => { let {height, weight, wealth} = man if (height > 180 && weight > 70 && wealth > 100000) return 'Great!' return 'not good enough ...' }, () => { console.log(`they say i am ${man.isGreat}`) }) |
这就是vue中的一个依赖对应多个Watcher
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
解决ant design vue中树形控件defaultExpandAll设置无效的问题
这篇文章主要介绍了解决ant design vue中树形控件defaultExpandAll设置无效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-10-10Vue element-ui中表格过长内容隐藏显示的实现方式
在Vue项目中,使用ElementUI渲染表格数据时,如果某一个列数值长度超过列宽,会默认换行,造成显示不友好,下面这篇文章主要给大家介绍了关于Vue element-ui中表格过长内容隐藏显示的实现方式,需要的朋友可以参考下2022-09-09关于vue的npm run dev和npm run build的区别介绍
这篇文章主要介绍了关于vue的npm run dev和npm run build的区别介绍,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2019-01-01Vue axios全局拦截 get请求、post请求、配置请求的实例代码
这篇文章主要介绍了Vue axios全局拦截 get请求、post请求、配置请求的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下2018-11-11
最新评论