有使用過vm.$set嗎,原理是什么?
vm.$set 是 Vue.js 提供的一個方法,用于在 Vue 實例中動態(tài)添加響應(yīng)式屬性。它的主要作用是確保新添加的屬性能夠被 Vue 的響應(yīng)式系統(tǒng)監(jiān)測到,從而觸發(fā)視圖的更新。
使用示例
假設(shè)我們有一個 Vue 實例
var vm = new Vue({
data: {
user: {
name: 'Alice'
}
}
});
我們希望在 user 對象中添加一個新的屬性 age。直接添加不會觸發(fā)視圖更新
vm.user.age = 25; // 直接添加不會觸發(fā)視圖更新
為了確保新添加的屬性是響應(yīng)式的,可以使用 vm.$set
vm.$set(vm.user, 'age', 25);
原理
Vue 的響應(yīng)式系統(tǒng)是基于 Object.defineProperty 實現(xiàn)的。當(dāng)一個對象被添加到 Vue 實例的 data 中時,Vue 會遞歸地遍歷該對象的所有屬性,并使用 Object.defineProperty 將這些屬性轉(zhuǎn)換為 getter 和 setter,從而實現(xiàn)響應(yīng)式。然而,直接添加的新屬性并沒有通過這種方式定義,因此 Vue 無法檢測到這些新屬性的變化。vm.$set 方法內(nèi)部使用了 Vue 的 set 方法,它會確保新添加的屬性也能通過 Object.defineProperty 轉(zhuǎn)換為響應(yīng)式屬性。
vm.$set 的實現(xiàn)
Vue 源碼中 set 方法的實現(xiàn)(Vue 2.x)大致如下:
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;
}
function defineReactive(obj, key, val) {
const dep = new Dep();
let childOb = observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
}
}
return value;
},
set: function reactiveSetter(newVal) {
const value = val;
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
val = newVal;
childOb = observe(newVal);
dep.notify();
}
});
}
總結(jié)
vm.$set 方法在 Vue 中用于動態(tài)添加響應(yīng)式屬性,確保新屬性能夠被 Vue 的響應(yīng)式系統(tǒng)監(jiān)測到。它通過 Object.defineProperty 將新屬性定義為響應(yīng)式屬性,并觸發(fā)依賴更新,確保視圖能夠正確更新。
使用工具學(xué)會使用只是第一步,掌握原理并能夠通過原理解決問題才是關(guān)鍵,在平時的開發(fā)中,使用時多數(shù),然而在遇到復(fù)雜問題或者優(yōu)化時候掌握原理會提高開發(fā)效率。