「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。
vue2的实现(3)之对象的劫持
回顾
- 上次内容我们介绍了
rewrite-vue/src/state.js,这个文件中主要做的就是对数据状态的初始化,下面是这个文件夹中的代码,我们拿到data后,接下来就到了对数据的劫持操作了。 rewrite-vue/src/state.jsexport 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 console.log(data) }
实现对象的劫持
- 我们接着完成
initData的方法,我们拿到用户传入的data数据之后,需要劫持对象属性的getset,通过observe方法来观测数据. 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 observe(data) }observe是一个独立的模块,我们需要拆分出去,新建rewrite-vue/src/observe文件夹.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){ Object.defineProperty(target, key, { get(){ console.log('劫持用户的取值操作,get'); return value }, set(newValue){ if(newValue !== value){ console.log('劫持用户的设置操作,set'); value = newValue } } }) } export function observe(data){ if(typeof data !== 'object' || data === null){ return } return new Observe(data) }observe方法,主要是对对象类型的数据做劫持,返回一个Observe的实例,把数据传进去,consturctor中默认会调用walk方法,walk方法的作用是循环遍历对象,调用defineReactive方法,传入三个参数,target是要劫持的目标对象,key要劫持的属性,value劫持的属性对应的值.因为defineReactive方法需要暴露出去,所以这个方法,拆出来写,不写在Observe类中.defineReactive方法的作用是劫持属性的getset在用户获取值,设置值的时候我们可以拦截到用户的操作.
测试
在上面的代码rewrite-vue/src/observe/index.js中,我们在get set 中做了打印操作,可以来测试一下我们的代码.
-
命令行输入
npm run dev,打包文件到dist目录下 -
在浏览器打开
dist/index.html -
打开浏览器控制台,在控制台获取或者设置我们传入的
data数据 -
由于我们在
src/state.js的initData方法中给vm._data赋值为我们传入的data,也就是劫持过的data,我们可以直接通过vm._data去访问数据,vm就是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:3 } }) </script> </body> </html> -
从下面的图可以看出我们的打印已经生效了,证明我们已经拦截到了对象的获取与设置
今天是更文第十天加油~ 看到这里兄弟帮忙点个赞吧