<template>
<div >
<p v-for="(value,index) in item" :key="index">{{ value }}</p>
<button @click="addProperty">动态添加属性</button>
</div>
</template>
<script>
export default {
data () {
return {
item: {
oldProperty: '旧属性'
}
}
},
methods: {
addProperty () {
this.item.newProperty = '新属性'
console.log(this.item)
}
}
}
</script>
上面的代码我我们的预期结果是点击一下button按钮,就给item对象添加一个新的属性,可是在控制台上确实输出了新属性,但是页面却不发生更新!这是为什么呢?
1.原理分析
vue2采用defineProperty实现数据响应式
const obj = {}
Object.defineProperty(obj, 'foo', {
get() {
console.log(`get foo:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
console.log(`set foo:${newVal}`);
val = newVal
}
}
})
当我们访问obj的属性时,都能触发getter和setter,但当我们为obj添加属性时,却没有触发事件属性的拦截
原因是一开始obj的属性是响应式的,一开始就被监听,而后新添加的属性,没有被监听,所以不是响应式数据。
2.解决方案
Vue不允许在已经创建的实例上动态的添加新的响应式属性
若想要实现试图更新,可采用以下三种方案
2.1 Vue.set()
Vue.set(target,propertyName/index,value)
<template>
<div >
<p v-for="(value,index) in item" :key="index">{{ value }}</p>
<button @click="addProperty">动态添加属性</button>
</div>
</template>
<script>
import Vue from 'vue'// 记得引入,默认导入
export default {
data () {
return {
item: {
oldProperty: '旧属性'
}
}
},
methods: {
addProperty () {
console.log(Vue)
Vue.set(this.item, 'newProperty', '新属性')// 属性是字符串
console.log(this.item)
}
}
}
</script>
2.2 Vue.forceUpdate()
<template>
<div >
<p v-for="(value,index) in item" :key="index">{{ value }}</p>
<button @click="addProperty">动态添加属性</button>
</div>
</template>
<script>
export default {
data () {
return {
item: {
oldProperty: '旧属性'
}
}
},
methods: {
addProperty () {
this.item.newProperty = '新属性'
this.$forceUpdate()
console.log(this.item)
}
}
}
</script>
2.3 Object.assign()
<template>
<div >
<p v-for="(value,index) in item" :key="index">{{ value }}</p>
<button @click="addProperty">动态添加属性</button>
</div>
</template>
<script>
export default {
data () {
return {
item: {
oldProperty: '旧属性'
}
}
},
methods: {
addProperty () {
this.item = Object.assign({}, this.item, { newProperty: '新属性' })
console.log(this.item)
}
}
}
</script>