持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
前言
学习框架,仅仅会使用是不够的,想要更熟悉框架,需要对源码有一定的了解。本篇文章通过vue源码解析,实现vue的data劫持。
介绍
Object.defineProperty(obj,prop,descriptor) 用法介绍:
-
参数
-
obj:要定义属性的对象。 -
prop:要定义或修改的属性的名称 -
descriptor:要定义或修改的属性描述符。
-
-
描述符值汇总
configurable:当且仅当该属性的configurable键值为true时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为false。enumerable:属性为true时,属性才会出现在对象中的枚举属性中value:属性对应的值get:属性的getter函数,如果没有getter,则为undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入this对象set:属性的setter函数,如果没有setter,则为undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的this对象。writable:当属性的值为true时,属性的值才能被修改
什么是数据劫持?
数据劫持,指用户操作数据时,通过代码进行拦截,然后在用户操作的基础上,再添加一些额外的操作
在Vue中,数据劫持就是用过Object.defineProperty中的getter和setter实现的,当数据发生改变,就通知Vue调用getter和setter方法,对数据做进一步处理。
实现
在上一篇文章中,我们已经能通过this获取到Vue对象了,但是不能获取this中指定的属性
当我们打印this.message时,输出的时undefined,原因是因为this里面没有message,message只存在于data中
所以,我们需要将data中的数据,复制到vue对象中,像这样:
并且,还要让data中的数据,和Vue对象中的数据,保存同步更新,例如:this.$data.message改变为'hello',this.message也要改变为'hello'
这里就需要用到Object.defineProperty(),进行数据劫持,Object.defineProperty()的使用上面已经介绍过了
我们需要实现的两个功能:
- 将
data中的属性值,赋值给vue对象 data中的属性值,和vue对象中的属性值,保存同步更新
思路:通过循环
$data中的属性值,并设置get和set,对数据进行劫持
代码
constructor(options) {
...
// 数据劫持
this.proxy()
}
// 数据劫持
proxy() {
for (let key in this.$data) {
Object.defineProperty(this, key, {
get() {
return this.$data[key]
},
set(value) {
this.$data[key] = value
}
})
}
}
并且可以获取到this.message
当我们对值进行修改时,vue对象中的值也会跟着改变
methods: {
handle(e) {
this.message = 'hellow'
console.log(this)
}
}
点击前
点击后
可以看出,当我们修改this.message中属性值时,this.$data.message也会跟着改变
到这里,我们就已经完成了data劫持了
但是,模板中还没有响应式更新,在下一篇文章会讲 vue中视图更新
总结
实现data劫持,需要完成两个功能:
- 将
data中的属性值,赋值给vue对象 ata中的属性值,和vue对象中的属性值,保存同步更新
实现的方法是通过Object.defineProperty中的get和set进行数据劫持