我們知道通過object.defineproperty()劫持陣列為其設定getter和setter後,呼叫的陣列的push、splice、pop等方法改變陣列元素時並不會觸發陣列的setter,這就會造成使用上述方法改變陣列後,頁面上並不能及時體現這些變化,也就是陣列資料變化不是響應式的(對上述不了解的可以參考這篇文章)。但實際用vue開發時,對於響應式陣列,使用push、splice、pop等方法改變陣列時,頁面會及時體現這種變化,那麼vue中是如何實現的呢?
通過vue原始碼可以看出,vue重寫了陣列的push、splice、pop等方法。
重寫完陣列的上述7種方法外,我們還需要將這些重寫的方法應用到陣列上,因此在observer建構函式中,可以看到在監聽資料時會判斷資料型別是否為陣列。當為陣列時,如果瀏覽器支援__proto__,則直接將當前資料的原型__proto__指向重寫後的陣列方法物件arraymethods,如果瀏覽器不支援__proto__,則直接將arraymethods上重寫的方法直接定義到當前資料物件上;當資料型別為非陣列時,繼續遞迴執行資料的監聽。12
3456
78910
1112
1314
1516
1718
1920
2122
2324
2526
2728
2930
3132
// src/core/observer/index.js
export class observer else
this.observearray(value)
} else
}...
}function protoaugment (target, src: object)
function copyaugment (target: object, src: object, keys: array)
}經過上述處理後,對於陣列,當我們呼叫其方法處理陣列時會按照如下原型鏈來獲取陣列方法:
對於響應式陣列,當瀏覽器支援__proto__屬性時,使用push等方法時先從其原型arraymethods上尋找push方法,也就是重寫後的方法,處理之後陣列的變化會通知到其訂閱者,更新頁面,當在arraymethods上查詢不到時會向上在array.prototype上查詢;當瀏覽器不支援__proto__屬性時,使用push等方法時會先從陣列自身上查詢,如果查詢不到會向上再array.prototype上查詢。
對於非響應式陣列,當使用push等方法時會直接從array.prototype上查詢。
值得一提的是原始碼中通過判斷瀏覽器是否支援__proto__來分別使用protoaugment和copyaugment 方法將重寫後的陣列方法應用到陣列中,這是因為對於ie10及以下的ie瀏覽器是不支援__proto__屬性的:
上述截圖參考於vue原始碼解析五——資料響應系統
結論:在將陣列處理成響應式資料後,如果使用陣列原始方法改變陣列時,陣列值會發生變化,但是並不會觸發陣列的setter來通知所有依賴該陣列的地方進行更新,為此,vue通過重寫陣列的某些方法來監聽陣列變化,重寫後的方法中會手動觸發通知該陣列的所有依賴進行更新。
如果我的內容能對你有所幫助,我就很開心啦!
以上就是vue中是怎樣監聽陣列變化的的詳細內容
vue中是如何監聽陣列變化?
我們知道通過object.defineproperty 劫持陣列為其設定getter和setter後,呼叫的陣列的push splice pop等方法改變陣列元素時並不會觸發陣列的setter,這就會造成使用上述方法改變陣列後,頁面上並不能及時體現這些變化,也就是陣列資料變化不是響應式的 對上述不了...
vue監聽陣列變化
1 觸發更新檢視 2function updateview 56 重新定義陣列原型 7 const oldarrayproperty array.prototype8 建立新物件,原型指向 oldarrayproperty 再擴充套件新的方法不會影響原型 9 const arrproto objec...
vue監聽陣列 物件變化
1.vue單獨監聽乙個陣列或者乙個物件變化 watch 2.如果你想監聽乙個陣列中多個物件是否變化,請看這裡!watch 沒錯!新增乙個deep true就可以實現對乙個陣列中多個物件是否變化進行監聽啦?3.watch中除了deep外,還有乙個屬性immediate immediate表示在watc...