「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。
vue2的实现(6)之将数据代理到Vue的实例上
回顾
-
上次内容我们处理了一个问题,假如用户传入的数据
data,是深层嵌套的,那我们之前写的逻辑就劫持不到用户的操作,所以我们需要在rewrite-vue/src/observe/index.js中的defineReactive方法中,再次对对象的每个属性值进行监测,我们只需要每次在对传入的value进行observe(value)操作即可。这样我们就可以进行深层递归劫持了,下面是我们上次完成的代码。 -
rewrite-vue/src/observe/index.jsclass Observe { consturctor(data){ this.walk(data) } walk(data){ Object.keys(data).forEach(key => defineReactive(data, key, data[key])) } } export function defineReactive(target, key, value){ observe(value) Object.defineProperty(target, key, { get(){ console.log('劫持用户的取值操作,get'); return value }, set(newValue){ if(newValue !== value){ console.log('劫持用户的设置操作,set'); observe(newValue) value = newValue } } }) } export function observe(data){ if(typeof data !== 'object' || data === null){ return } return new Observe(data) }
如何将数据代理到Vue的实例上
-
我们用下面的代码测试一下,在浏览器打开
rewrite-vue/dist/index.html。 -
rewrite-vue/dist/index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue2</title> </head> <body> <script src="./vue.js"></script> <script> const vm = new Vue({ data:{ name:'vue2', age: { num:666, key:'age' } } }) console.log(vm.name); </script> </body> </html> -
下面的图片是输出结果,我们可以看到打印的结果是
undefined。 -
我们在使用
Vue的时候,可以从实例上直接访问到数据data,而不需要从vm._data去取值。 -
当我们访问
vm实例上的属性的时候,我们需要把他代理到_data上。 -
因为这个操作属于处理数据的操作,和我们的
observe模块并不是一个模块。所以我们把他放到rewrite-vue/src/state.js中,在我们初始化数据的initData方法中去做。 -
我们写一个专门的方法来做这件事情,这个方法叫做
proxy,proxy方法接受两个参数,一个是vm实例,一个是我们在vm访问属性时,要代理的目标对象的名称,这个方法我们以后也可以用来代理props、computed。 -
proxy方法的作用就是,循环遍历所有的目标对象属性,把所有的属性代理到vm实例上。 -
rewrite-vue/src/state.jsimport {observe} from './observe' export function initState(vm) { const opts = vm.$options if (opts.data) { initData(vm) } } function initData(vm) { let data = vm.$options.data data = typeof data === 'function'? data.call(vm) : data vm._data = data proxy(vm, '_data') observe(data) } function proxy(vm, target){ for(let key in vm[target]){ Object.defineProperty(vm,key,{ get(){ return vm[target][key] }, set(newValue){ vm[target][key] = newValue } }) } }
测试
-
rewrite-vue/dist/index.html里面的代码还是上面的测试用例,我们再次在浏览器中打开rewrite-vue/dist/index.html。 -
从下面的图可以看出我们的打印已经生效了,证明我们已经把
_data属性代理到了vm实例上。今天是更文第十三天加油~ 看到这里兄弟帮忙点个赞吧