# Vue $set 怎么實現給數組集合對象賦值
## 一、Vue 響應式原理與 $set 的誕生背景
### 1.1 Vue 的響應式系統局限性
Vue 2.x 使用 `Object.defineProperty` 實現響應式,這種實現存在兩個主要限制:
1. **無法檢測對象屬性的添加/刪除**
2. **數組變更的特殊情況**:
- 通過索引直接設置項(`arr[index] = newValue`)
- 修改數組長度(`arr.length = newLength`)
### 1.2 為什么需要 $set
當我們需要動態給響應式對象添加新屬性,或修改數組特定索引的值時,直接賦值不會觸發視圖更新。這時就需要使用 `Vue.set` 或實例方法 `this.$set`。
```javascript
// 不會觸發更新
this.arr[1] = 'new value'
this.obj.newProp = 'value'
// 正確做法
this.$set(this.arr, 1, 'new value')
this.$set(this.obj, 'newProp', 'value')
$set 方法定義在 src/core/observer/index.js 中:
export function set(target, key, val) {
// 處理數組情況
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
// 處理對象已有屬性
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
// 處理新增對象屬性
const ob = target.__ob__
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}
對于數組操作,$set 內部實際上使用了 splice 方法,這是因為 Vue 重寫了數組的變異方法(push/pop/shift/unshift/splice/sort/reverse),使得這些方法能夠觸發響應式更新。
// 等效操作
this.$set(arr, index, value)
// 等同于
arr.splice(index, 1, value)
export default {
data() {
return {
user: {
name: '張三'
}
}
},
methods: {
addAge() {
// 錯誤方式
// this.user.age = 25 // 不會響應
// 正確方式
this.$set(this.user, 'age', 25)
}
}
}
export default {
data() {
return {
items: ['a', 'b', 'c']
}
},
methods: {
updateItem(index) {
// 錯誤方式
// this.items[index] = 'x' // 不會響應
// 正確方式
this.$set(this.items, index, 'x')
// 替代方案(同樣有效)
// this.items.splice(index, 1, 'x')
}
}
}
export default {
data() {
return {
formData: {}
}
},
methods: {
initForm() {
// 多層嵌套需要逐層設置
this.$set(this.formData, 'contact', {})
this.$set(this.formData.contact, 'phone', '')
}
}
}
在 Vue 3 中,基于 Proxy 的響應式系統不再需要 $set:
import { reactive } from 'vue'
const state = reactive({})
state.newProp = 'value' // 自動響應
對于對象,可以創建新對象觸發更新:
this.user = Object.assign({}, this.user, { age: 25 })
對于數組,優先使用變異方法:
// 替換元素
this.items.splice(index, 1, newItem)
// 添加元素
this.items.push(newItem)
不能用于根級響應式屬性:
// 錯誤!不能直接添加根級屬性
this.$set(this, 'newProp', value)
性能考慮:
與 v-model 的配合: “`html
## 六、總結
`$set` 是 Vue 2.x 響應式系統的重要補充,它解決了以下關鍵問題:
- 動態添加響應式屬性
- 數組索引直接賦值
- 確保嵌套屬性的響應性
在 Vue 3 中,由于 Proxy 的實現,大多數情況下不再需要 `$set`,但在 Vue 2.x 項目中,它仍然是處理動態響應式數據的利器。
**最佳實踐建議**:
1. 初始化時盡量聲明所有響應式屬性
2. 必須動態添加時優先使用 `$set`
3. 數組操作優先使用變異方法
4. 復雜數據結構考慮使用 Vuex 或 Pinia 管理狀態
通過合理運用 `$set` 方法,可以確保你的 Vue 應用始終保持正確的響應式行為。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。