標籤:

為什麼直接修改數組長度或設置數組項的索引時,Vue不能檢測到數組的變動?

列表渲染 - vue.js注意事項

由於 JavaScript 的限制, Vue 不能檢測以下變動的數組:

當你直接設置一個項的索引時, 例如: vm.items[indexOfItem] = newValue

當你修改數組的長度時, 例如: vm.items.length = newLength


因為沒有辦法監聽任意屬性。

當然現在Proxy是可以做到這點的,不過一個是兼容性問題,另一個是如果用了Proxy就是一個新對象,跟現在Vue在原本對象上設置 getter/setter 的方式不同。


正好看到 @廖雪峰的博客中說過這個問題

需要注意的是,Vue之所以能夠監聽Model狀態的變化,是因為JavaScript語言本身提供了Proxy或者Object.observe()機制來監聽對象狀態的變化。但是,對於數組元素的賦值,卻沒有辦法直接監聽,因此,如果我們直接對數組元素賦值:

vm.todos[0] = {
name: "New name",
description: "New description"
};

會導致Vue無法更新View。

正確的方法是不要對數組元素賦值,而是更新:

vm.todos[0].name = "New name";
vm.todos[0].description = "New description";

或者,通過splice()方法,刪除某個元素後,再添加一個元素,達到「賦值」的效果:

var index = 0;
var newElement = {...};
vm.todos.splice(index, 1, newElement);

Vue可以監聽數組的splice、push、unshift等方法調用,所以,上述代碼可以正確更新View。


vue用defineproperty下的setter和getter方法做依賴跟蹤的。

MDN:

數組的 length 屬性重定義是可能的,但是會受到一般的重定義限制。(length 屬性初始為 non-configurable,non-enumerable 以及 writable。對於一個內容不變的數組,改變其 length 屬性的值或者使它變為 non-writable 是可能的。但是改變其可枚舉性和可配置性或者當它是 non-writable 時嘗試改變它的值或是可寫性,這兩者都是不允許的。)然而,並不是所有的瀏覽器都允許 Array.length 的重定義。

簡單來說length的命名訪問器屬性set和get你不能動它,也就無法設置setter和getter

至於數組下的索引是可以用setter和getter的

但是為啥vue下索引也不允許更新呢?因為length = 5的數組,未必索引就有4,這個索引(屬性)不存在,就沒法setter了。


因為用的是 Object.defineProperty 實現的啊…


我是來問問題的。

我用一個數組 results 現實一個表格;當我需要重新搜索數據時,

我首先使用results.splice(0),把這個數組清空了,然後用ajax重新獲取數據填充了

數組results,這個時候渲染的時候總是出錯。

但如果我在頁面上弄個「清空」按鈕,點下這個按鈕後,也是執行results.splice(0),把數組清空了。

然後再點另外一個按鈕,重新獲取數據到results裡面。就一切都正常了。

我試過在 results.splice(0); 後執行 vm.$forceUpdate(0),也沒用。

能給個解決的方法么?我就是希望能點擊一個按鈕執行清空數組,然後重新獲取數據的操作。


推薦閱讀:

做為一個初級前端,我要花多久時間學習vue才能在項目中用它?
vue子組件用父組建方法改變執行上下文環境的問題?
歷史遺留項目,如何採用vue+webpack的形式改造呢?
Vue.js 官方中文文檔寫的很爛嗎?

TAG:JavaScript | Vuejs |