Vue2源碼解讀 - $set()使用及實現原理
- 當我們給響應式的對象新增屬性時,新增的屬性並不會渲染到頁面中
- 對於響應式的數組,增加元素、修改數組長度時,數組的這些變化也不會反映到頁面中
那么如何讓新增的對象或數組實現響應式及時渲染頁面呢?
使用this.$set()
官方定義
Vue 不允許在已經創建的實例上動態添加新的根級響應式屬性 (root-level reactive property)。然而它可以使用 Vue.set(object, key, value)
方法將響應屬性添加到嵌套的對象上
// Vue.set(object, key, value)
<template>
<div>{{obj.k}}</div>
</template>
<script>
export default {
data() {
return {
obj: {
s: '1',
z: '2'
}
}
},
mounted() {
this.$set(this.obj, 'k', '3')
}
}
</script>
$set原理
直接看源碼
function set(target: Array<any> | Object, key: any, val: any): any {
// isUndef 是判斷 target 是不是等於 undefined 或者 null 。
//isPrimitive 是判斷 target 的數據類型是不是 string、number、symbol、boolean 中的一種
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
) {
warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
}
// 數組的處理
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
}
// vue給響應式對象(比如 data 里定義的對象)都加了一個 __ob__ 屬性,
// 如果一個對象有這個 __ob__ 屬性,那么就說明這個對象是響應式對象,我們修改對象已有屬性的時候就會觸發頁面渲染。
// 非 data 里定義的就不是響應式對象。
const ob = (target: any).__ob__
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== 'production' && warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.'
)
return val
}
// 不是響應式對象
if (!ob) {
target[key] = val
return val
}
// 是響應式對象,進行依賴收集
defineReactive(ob.value, key, val)
// 觸發更新視圖
ob.dep.notify()
return val
}