面试题答案
一键面试Vue.set
或 this.$set
使对象新增属性变为响应式的原理
-
Vue的响应式原理基础:Vue 在初始化数据时,会使用
Object.defineProperty
方法对数据对象的属性进行遍历,将每个属性转换为getter
和setter
。当数据被访问或修改时,getter
和setter
会被触发,从而实现数据的响应式追踪。 -
问题产生:对于对象在创建之后新添加的属性,Vue 无法在初始化时为其设置
getter
和setter
,所以默认情况下新属性不会是响应式的,视图也不会因为新属性的变化而更新。 -
Vue.set
或this.$set
的原理:Vue.set
实际上是全局 Vue 实例的一个方法,this.$set
是组件实例上的方法,它们本质是相同的。其原理是:- 首先判断目标对象是否是 Vue 实例或者 Vue 实例的根数据对象,如果是则抛出警告,因为不能直接在 Vue 实例或根数据对象上添加响应式属性。
- 然后判断要添加属性的对象是否为数组,如果是数组,则使用
splice
方法来触发数组的响应式更新。 - 对于普通对象,使用
Object.defineProperty
方法为对象添加新的属性,并为其设置getter
和setter
,从而使其变为响应式。同时,会通知依赖收集器,让相关的视图进行更新。
实际开发中提升开发效率的示例
假设我们有一个电商商品详情页面,商品数据包括基本信息(名称、价格等)和一个动态的属性列表(例如颜色、尺寸等),这些动态属性可能会根据用户操作动态添加。
<template>
<div>
<h1>{{ product.name }}</h1>
<p>价格: {{ product.price }}</p>
<ul>
<li v-for="(attr, index) in product.attributes" :key="index">{{ attr.name }}: {{ attr.value }}</li>
</ul>
<button @click="addAttribute">添加属性</button>
</div>
</template>
<script>
export default {
data() {
return {
product: {
name: '示例商品',
price: 100,
attributes: []
}
};
},
methods: {
addAttribute() {
const newAttr = { name: '新属性', value: '新值' };
// 使用 this.$set 使新添加的属性变为响应式
this.$set(this.product.attributes, this.product.attributes.length, newAttr);
}
}
};
</script>
在这个例子中,当用户点击“添加属性”按钮时,会动态向 product.attributes
数组中添加一个新的属性对象。如果不使用 this.$set
,视图不会因为新属性的添加而更新。使用 this.$set
后,视图能够实时反映出数组的变化,用户可以立即看到新添加的属性,大大提升了开发效率,尤其是在处理复杂的动态数据更新且需要视图同步变化的场景。