Vue 中的 $set
方法(Vue.set
)主要用于 向響應式對象中添加一個新的屬性,并確保這個新屬性是響應式的,能夠觸發視圖更新。
📌 背景問題:為什么需要 $set
?
在 Vue 2 中,直接給對象新增屬性不會觸發視圖更新,例如:
this.obj.a = 123 // 如果 a 原本不存在,則不會觸發視圖更新
這是因為 Vue 2 是基于 Object.defineProperty
來實現響應式系統的,它在對象初始化時只能“劫持”已有屬性,無法監控新增的屬性。
? $set
的作用
this.$set(obj, key, value)
或者
Vue.set(obj, key, value)
它的作用是:
-
為對象添加新屬性
-
讓這個新屬性是響應式的
-
觸發視圖更新
🧠 原理解析(Vue 2)
Vue.set = function (target, key, val) {if (Array.isArray(target) && isValidIndex(key)) {// 對數組使用 splice 替代設置target.splice(key, 1, val)return val}if (key in target && !(key in Object.prototype)) {target[key] = valreturn val}const ob = target.__ob__ // 這是 Observer 實例if (!ob) {target[key] = valreturn val}defineReactive(ob.value, key, val) // 核心:為新屬性定義響應式ob.dep.notify() // 通知依賴更新return val
}
核心步驟:
-
判斷是否是數組:數組用
splice
替代賦值(因為 Vue 對數組的監聽基于方法攔截)。 -
通過
defineReactive()
為新屬性添加 getter/setter,注入依賴收集邏輯。 -
通知依賴更新視圖(
dep.notify()
)
🧪 示例
<template><div>{{ user.name }}</div><button @click="addProp">添加新屬性</button>
</template><script>
export default {data() {return {user: {}}},methods: {addProp() {this.$set(this.user, 'name', '張三') // 觸發視圖更新}}
}
</script>
🆕 Vue 3 呢?
在 Vue 3 中,由于使用了 Proxy 實現響應式,不需要 $set
了,你可以直接賦值:
reactiveObj.newKey = 123 // ? 直接響應式,無需 $set
🧩 總結
項目 | Vue 2 | Vue 3 |
---|---|---|
添加響應式屬性 | 需要 $set | 不需要,直接賦值即可 |
實現機制 | Object.defineProperty + defineReactive | Proxy 攔截所有操作 |
數組監聽 | 依賴重寫 push/splice 等方法 | Proxy 完整攔截 |
需要我幫你用簡單代碼實現一個簡化版的 $set
嗎?可以更好理解它的內部邏輯。