深入理解 options.data
前置1:ES 6的getter和setter
getter、setter用于对属性的读写进行监控
let obj = {
姓:'高',
名: '圆圆',
get 姓名(){
return this.姓 + this.名
},
set 姓名(name){
this.姓 = name[0]
this.名 = name.slice(1)
}
}
obj.姓名 //'高圆圆'
obj.姓名 = '高媛媛'
obj.姓名 //'高媛媛'
姓名
属性实际是不存在的(可视为虚拟对象),它是计算出来的属性
obj.姓名
--> 获取get 姓名
方法的返回值obj.姓名 = 'xxx'
--> 调用obj.set 姓名('xxx')
前置2:Object.defineProperty
作用:给对象新增属性,也可以添加getter、setter属性
let obj = {}
Object.defineProperty(obj, 'x', {value: 1}) //添加属性'x'
Object.defineProperty(obj, 'y', {
get(){...},
set(value){...}
})
// 添加虚拟的属性'y'
案例:
设计模式--代理,用新对象newData
代理原对象oldData
,以实现用newData.n
来操作oldData.n
let oldData = {n:0}
let newData = proxy({data: oldData})
function proxy({data}){ //解构赋值
let value = data.n
Object.defineProperty(data, 'n', {
get(){
return value
},
set(newValue){
value = newValue
}
})
//监听 oldData,防止 oldData 直接被篡改
let obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(newValue){
data.n = newValue
}
})
//令 newData 代理 oldData
return obj
}
即newData.n
----操作----> oldData.n
----操作----> value
无论直接操作oldData.n
还是操作newData.n
,newData
都可以收到通知
Vue 对 data 做了什么
Vue 的 data 是响应式的
const vm = new Vue({data: myData})
后,myData 被改造:
- 令 vm 成为 myData 的代理
- 对 myData 的所有属性进行监控(即变为getter/setter)
目的: 无论直接修改myData.n
还是修改vm.n
,vm 都会收到通知,然后调用触发重新渲染
Vue 对 methods 和 computed 也有类似的处理
data 的 bug
Vue 通过Object.defineProperty(obj, 'n', {...})
实现数据的响应式,data
有属性'n'
才可以监听&代理data.n
,若无属性'n'
,则会产生问题
无data.n
new Vue({
data: {},
template: `
<div>{{n}}</div>
`
}).$mount("#app");
无data.n
(或有但为undefined)但被引用,不会显示,且报警告
有data.obj
,但无data.obj.n
const vm = new Vue({
data: {
obj: {
a: 0 // obj.a 会被 Vue 监听 & 代理
}
},
template: `
<div>
{{obj.n}}
<button @click="setN">set n</button>
</div>
`,
methods: {
setN() {
this.obj.n = 1;
}
}
}).$mount("#app");
data.obj
中一开始没有'n'
,此后给vm添加属性vm.obj.n = 1
并不会出现在页面中,因为vm没有监听&代理data.obj.n
解决:
1.在一开始定义好data.obj.n = undefined
(推荐)
2.若后续添加属性,只能用Vue.set
或this.$set
(两者等价),它可以为新增的属性添加代理&监听
methods: {
setN(){
Vue.set(this.obj, 'n', 1)
//或
this.$set(this.obj, 'n', 1)
}
}
给 data 中的数组添加元素
直接为数组添加元素,也不会渲染到页面
new Vue({
data: {
array: ["a", "b", "c"]
},
template: `
<div>
{{array}}
<button @click="setD">set d</button>
</div>
`,
methods: {
setD() {
this.array[3] = "d";
}
}
}).$mount("#app");
同对象一样,用Vue.set
或vm.$set
新增元素,也可以触发视图更新
用this.array.push('d')
,也能更新
经过 Vue 的数组,其方法会被篡改,称为变异方法,这些方法会自动为新增元素添加代理&监听,更新视图
数组变异方法有7个:push
pop
unshift
shift
splice
sort
reverse
总是推荐使用变异方法对数组进行增删