在開發過程中,我們時常會遇到這樣一種情況:當vue的data裡邊宣告或者已經賦值過的物件或者陣列(陣列裡邊的值是物件)時,向物件中新增新的屬性,如果更新此屬性的值,是不會更新檢視的。
根據官方文件定義:如果在例項建立之後新增新的屬性到例項上,它不會觸發檢視更新。 受現代 JavaScript 的限制 (以及廢棄 Object.observe),Vue 不能檢測到物件屬性的新增或刪除。由於 Vue 會在初始化例項時對屬性執行 getter/setter 轉化過程,所以屬性必須在 data 物件上存在才能讓 Vue 轉換它,這樣才能讓它是響應。
當然針對這種情況,官方也提供瞭解決方案,如下: Vue 不允許在已經建立的例項上動態新增新的根級響應式屬性 (root-level reactive property)。然而它可以使用Vue.set(obj, key, val)方法將響應屬性新增到巢狀的物件上: Vue.set(vm.obj, 'e', 0) 您還可以使用 vm.$set 例項方法,這也是全域性 Vue.set 方法的別名: this.$set(this.obj, 'e', 2)
那麼為什麼會這樣呢?還是要從Vue實現資料繫結的原理說起(Object.defineProperty),假設我們把Vue資料繫結精簡為下列程式碼:
<div>
<h3>展示姓名:<span id="name"></span></h3>
<p>輸入姓名:<input type="text" oninput="inputHandler('name', this.value)" /></p>
<h3>展示電話號碼:<span id="phone"></span></h3>
<p>輸入電話號碼:<input type="text" oninput="inputHandler('phone', this.value)" /></p>
</div>
<script type="text/javascript">
// 需要監聽的物件 ----
var obj = {
name: null
}
// 定義監聽 - Object.defineProperty的實現
for(let key in obj) {
let val = obj[key];
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
return val;
},
set(newValue) {
if(val === newValue) {
return;
}
document.getElementById(key).innerText = newValue;
val = newValue;
}
})
}
var inputHandler = function(key, value) {
obj[key] = value;
}
</script>
複製程式碼
那麼重點來了,我們有沒有辦法實現新增屬性也能自動繫結呢?答案當然是有,也就是即將推出的Vue3.0也採用的ES6的新API - Proxy,用新的Proxy 改些後的程式碼如下:
<div>
<h3>展示姓名:<span id="name"></span></h3>
<p>輸入姓名:<input type="text" oninput="inputHandler('name', this.value)" /></p>
<h3>展示電話號碼:<span id="phone"></span></h3>
<p>輸入電話號碼:<input type="text" oninput="inputHandler('phone', this.value)" /></p>
</div>
<script type="text/javascript">
// 需要監聽的物件 ----
var obj = {
name: null
}
obj = new Proxy(obj, {
get: function(target, prop) {
console.log('proxy get:', target, prop);
},
set: function(target, prop, value) {
document.getElementById(prop).innerText = value;
target[prop] = value;
console.log('proxy:', target, prop, value);
}
})
var inputHandler = function(key, value) {
obj[key] = value;
}
</script>
複製程式碼
執行起來看看,是不是不使用$set,就能實現新增屬性的繫結呢?期待Vue3.0的到來。