Vue的Data
ES 6的setter和getter
对象属性也可以是一个函数、getter、setter方法。
语法
var o = {
property: function ([parameters]) {},
get property() {},
set property(value) {},
};
Object.defineProperty
作用:
- 可以给对象添加属性
value - 可以给对象添加
getter/setter,getter/setter用来对属性的读写进行监控
语法:
var o = {}; // 创建一个新对象
// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
代理模式
代理的设计模式,意思为vm实例负责对myData对象属性的读写。即vm就是myData的代理,类似于房屋中介,住户通过中介和房东交流。例如通常vm.n来操作myData.n,而不是直接操作myData.n
原理

const vm = new Vue({data: myData})
作用:
- 核心目的:对于data的任何变动,都得知情,从而重新进行渲染
- 会让
vm成为myData的代理,即proxy - 同时会对
myData的所有属性进行监控 - 监控的原因是,为了防止
myData属性改变的时候,vm不知情。如果通知vm了,就可以进行操作,然后调用render(data)方法,渲染视图,即UI=render(data) - 全程对
data进行修改,并没有复制和生成新的data,只有覆盖修改 - 如果
data有多个属性,n,m,k,那么就会有get n/get m /get k等
实例
下面的例子是类似原理,已经很完善了,但是不通过设置vm,通过设置另外一个引用,可以直接修改data的值。
let data3 = proxy({data:{n:0}})
function proxy({data}){ // 解构赋值
const obj = {}
// 这里的n进行了简化,理论上需要遍历data的所有key
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0) return
data.n = value
}
})
return obj // obj就是代理
}
这是最终的类似原理实现,实现了对data的监听和代理
let myData5 = {n: 0}
let data5 = proxy2({myData5})
function proxy2({data}){ // 解构赋值
let value = data.n
delete data.n //这行可以省略,下面的代码会覆盖data.n
// 这里的n进行了简化,理论上需要遍历data的所有key
Object.defineProperty(data, 'n', {
get(){
return value
},
set(newValue){
if(value<0) return
value = newValue
}
}) // 这里是监听逻辑
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
data.n = value
}
})
return obj // obj就是代理
}
const vm = new Vue({data:{n:0}) // 等价于let data5 = proxy2({myData5})
数据响应式
数据响应式是指当数据改变时,UI或者视图能够做出相应的反应。
data属于响应式
在const vm = new Vue({data:{n:0}})中,如果修改vm.n,那么UI中的n就会做出响应
Vue的数据响应式
Vue响应式系统即对数据进行修改时,视图会进行更新;
当把JS对象传入Vue实例作为 data 选项,Vue将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter,getter/setter 对用户不可见,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。
响应式网页
响应式网页是指当用户改变窗口大小,网页内容会做出响应
Vue的Bug
Object.defineProperty有问题
在Object.definePropery(obj, 'n', {...})时,必须要有一个'n',才能监听和代理obj.n。如果没有设置n,Vue会给出一个警告或者只会检查第一层属性 ,此时如果使用set方法,不会奏效,因为Vue没有办法监听一开始就不存在的属性。页面会显示空白
- 解决办法
- 事先声明
key,然后不再添加属性 - 使用
vue.set或者this.$set
对象中新增的key
Vue没有办法事先监听和代理,需要使用set来新增key,创建监听和代理,更新UI。推荐提前把属性都写好,不要新增key
Vue.set和this.$set
作用:
- 新增
key,即对象的键名或者属性名 - 如果没有创建过,自动创建代理和监听
- 触发
UI更新,但不会立刻更新,有延迟 实例:
methods:{
add({
vue.set(this.obj, 'b', 1)
// 或者
this.$set(this.obj, 'b', 1)
}
}
数组中新增的key
由于数组的长度可以一直增加,没有办法提前把数组的key都声明出来,Vue也不能检测新增的下标。可以使用set来新增key, 但不会自动添加监听和代理,然后更新UI。 但是尤雨溪纂改了7个API来对数组进行操作,这7个API会自动处理监听和代理,并更新UI。
推荐使用这7个API来新增数组key:
push()pop()shift()unshift()splice()sort()reverse()
使用代码模拟类似原理
class VueArray extends Array {
push(...args) {
const oldLength = this.length; // this
super.push(...args);
console.log(" push ");
for (let i = oldLength; i < this.length; i++) {
Vue.set(this, i, this[i]);
// key Vue
}
}
}