this.#set(obj, key, value)
我们在项目开发的过程中,经常会遇到这种情况:为data中的某一个对象添加一个属性
<template>
<div class="hello">
<button @click="setMessage">添加属性</button>
{{ student.name }}
<input type="text" v-model="student.age">
</div>
</template>
<script>
export default {
data() {
return {
student: {
name: '张三',
}
}
},
methods: {
setMessage() {
this.student.age = 15
console.log(this.student)
}
}
}
</script>
当我们点击按钮,为student添加一个age属性,看看视图层是否能够更新
在这里我们发现虽然这个对象身上已经有了该属性,但是视图层并没有更新该数据,是什么造成的呢?由于受JavaScript的限制,vue.js不能监听对象属性的添加和删除,因为在vue组件初始化的过程中,会调用getter和setter方法,所以该属性必须是存在在data中,视图层才会响应该数据的变化
那么,我们该如何解决这个问题呢
解决这个问题的方法大体有两种:使用this.$set(obj, key, value)/vue.set(obj, key, value)
调用方法:this.$set( target, key, value )
target:要更改的数据源(可以是对象或者数组) // 表示数据源,即是你要操作的数组或者对象
key:要更改的具体数据 //要操作的的字段
value :重新赋的值 //更改的数据
小案例:
给一个对象添加一个年龄属性并且让它可以响应式的进行改变
<template>
<div class="text">
<p>{{list}}</p>
<button @click="add">age++</button>
</div>
</template>
<script>
export default {
data(){
return {
list:{ name: "张三"}
}
},
methods: {
add(){
if(!this.list.age){ // 如果没有age属性就给它添加一个age属性
this.list.age=18
}else{
this.list.age++
}
console.log(this.list)
}
}
}
</script>
当我们没有使用this.$set
去添加对象属性的时候,效果:
数据确实已经添加进去了,但是页面并没有响应式的渲染age属性。
当我们使用this.$set(this.list,‘age',18)
去添加一个属性之后。效果:
我们能看见添加的数据是响应式的。
为什么能够响应式?
仔细观察一下,使用了this.$set 多了get age和set age方法,这正是能够响应式的原因
分析
Vue的响应式原理为 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,下图来自官方文档。
通过Object.assign(target, sources)方法
<script>
export default {
data() {
return {
student: {
name: '张三',
}
}
},
methods: {
setMessage() {
this.student.age = 15
this.student = Object.assign({}, this.student)
console.log(this.student)
}
}
}
</script>
我们发现,通过这两种方式为对象添加属性之后,他的对象身上多了get和set方法,所以,此时我们再次操作该属性的时候,就会引起视图的更新啦