新聞中心
現(xiàn)在是時候深入了!Vue 最獨特的特性之一,是其非侵入性的響應性系統(tǒng)。數(shù)據(jù)模型是被代理的 JavaScript 對象。而當你修改它們時,視圖會進行更新。這讓狀態(tài)管理非常簡單直觀,不過理解其工作原理同樣重要,這樣你可以避開一些常見的問題。在這個章節(jié),我們將研究一下 Vue 響應性系統(tǒng)的底層的細節(jié)。

網(wǎng)站建設哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、小程序定制開發(fā)、集團企業(yè)網(wǎng)站建設等服務項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了貴港免費建站歡迎大家使用!
在 Vue Mastery 上免費觀看關于深入響應性原理的視頻。
#什么是響應性
這個術語在程序設計中經(jīng)常被提及,但這是什么意思呢?響應性是一種允許我們以聲明式的方式去適應變化的一種編程范例。人們通常展示的典型例子,是一份 excel 電子表格 (一個非常好的例子)。
點擊此處看視頻
如果將數(shù)字 2 放在第一個單元格中,將數(shù)字 3 放在第二個單元格中并要求提供 SUM,則電子表格會將其計算出來給你。不要驚奇,同時,如果你更新第一個數(shù)字,SUM 也會自動更新。
JavaScript 通常不是這樣工作的——如果我們想用 JavaScript 編寫類似的內(nèi)容:
var val1 = 2
var val2 = 3
var sum = val1 + val2
// sum
// 5
val1 = 3
// sum
// 5如果我們更新第一個值,sum 不會被修改。
那么我們?nèi)绾斡?JavaScript 實現(xiàn)這一點呢?
- 檢測其中某一個值是否發(fā)生變化
- 用跟蹤 (track) 函數(shù)修改值
- 用觸發(fā) (trigger) 函數(shù)更新為最新的值
#Vue 如何追蹤變化?
當把一個普通的 JavaScript 對象作為 data 選項傳給應用或組件實例的時候,Vue 會使用帶有 getter 和 setter 的處理程序遍歷其所有 property 并將其轉(zhuǎn)換為 Proxy。這是 ES6 僅有的特性,但是我們在 Vue 3 版本也使用了 Object.defineProperty 來支持 IE 瀏覽器。兩者具有相同的 Surface API,但是 Proxy 版本更精簡,同時提升了性能。
點擊此處實現(xiàn)
該部分需要稍微地了解下 Proxy 的某些知識!所以,讓我們深入了解一下。關于 Proxy 的文獻很多,但是你真正需要知道的是 Proxy 是一個包含另一個對象或函數(shù)并允許你對其進行攔截的對象。
我們是這樣使用它的:new Proxy(target, handler)
const dinner = {
meal: 'tacos'
}
const handler = {
get(target, prop) {
return target[prop]
}
}
const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)
// tacos好的,到目前為止,我們只是包裝這個對象并返回它。很酷,但還不是那么有用。請注意,我們把對象包裝在 Proxy 里的同時可以對其進行攔截。這種攔截被稱為陷阱。
const dinner = {
meal: 'tacos'
}
const handler = {
get(target, prop) {
console.log('intercepted!')
return target[prop]
}
}
const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)
// tacos除了控制臺日志,我們可以在這里做任何我們想做的事情。如果我們愿意,我們甚至可以不返回實際值。這就是為什么 Proxy 對于創(chuàng)建 API 如此強大。
此外,Proxy 還提供了另一個特性。我們不必像這樣返回值:target[prop],而是可以進一步使用一個名為 Reflect 的方法,它允許我們正確地執(zhí)行 this 綁定,就像這樣:
const dinner = {
meal: 'tacos'
}
const handler = {
get(target, prop, receiver) {
return Reflect.get(...arguments)
}
}
const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)
// tacos 我們之前提到過,為了有一個 API 能夠在某些內(nèi)容發(fā)生變化時更新最終值,我們必須在內(nèi)容發(fā)生變化時設置新的值。我們在處理器,一個名為 track 的函數(shù)中執(zhí)行此操作,該函數(shù)可以傳入 target 和 key 兩個參數(shù)。
const dinner = {
meal: 'tacos'
}
const handler = {
get(target, prop, receiver) {
track(target, prop)
return Reflect.get(...arguments)
}
}
const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)
// tacos最后,當某些內(nèi)容發(fā)生改變時我們會設置新的值。為此,我們將通過觸發(fā)這些更改來設置新 Proxy 的更改:
const dinner = {
meal: 'tacos'
}
const handler = {
get(target, prop, receiver) {
track(target, prop)
return Reflect.get(...arguments)
},
set(target, key, value, receiver) {
trigger(target, key)
return Reflect.set(...arguments)
}
}
const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)
// tacos還記得幾段前的列表嗎?現(xiàn)在我們有了一些關于 Vue 如何處理這些更改的答案:
- 當某個值發(fā)生變化時進行檢測:我們不再需要這樣做,因為 Proxy 允許我們攔截它
- 跟蹤更改它的函數(shù):我們在 Proxy 中的 getter 中執(zhí)行此操作,稱為
effect - 觸發(fā)函數(shù)以便它可以更新最終值:我們在 Proxy 中的 setter 中進行該操作,名為
trigger
Proxy 對象對于用戶來說是不可見的,但是在內(nèi)部,它們使 Vue 能夠在 property 的值被訪問或修改的情況下進行依賴跟蹤和變更通知。從 Vue 3 開始,我們的響應性現(xiàn)在可以在獨立的包中使用。需要注意的是,記錄轉(zhuǎn)換后的數(shù)據(jù)對象時,瀏覽器控制臺輸出的格式會有所不同,因此你可能需要安裝 vue-devtools,以提供一種更易于檢查的界面。
#Proxy 對象
Vue 在內(nèi)部跟蹤所有已被設置為響應式的對象,因此它始終會返回同一個對象的 Proxy 版本。
從響應式 Proxy 訪問嵌套對象時,該對象在返回之前也被轉(zhuǎn)換為 Proxy:
const handler = {
get(target, prop, receiver) {
track(target, prop)
const value = Reflect.get(...arguments)
if (isObject(value)) {
return reactive(value)
} else {
return value
}
}
// ...
}#Proxy vs 原始標識
Proxy 的使用確實引入了一個需要注意的新警告:在身份比較方面,被代理對象與原始對象不相等 (===)。例如:
const obj = {}
const wrapped = new Proxy(obj, handlers)
console.log(obj === wrapped) // false在大多數(shù)情況下,原始版本和包裝版本的行為相同,但請注意,它們在依賴嚴格比對的操作下將是失敗的,例如 .filter() 或 .map()。使用選項式 API 時,這種警告不太可能出現(xiàn),因為所有響應式都是從 this 訪問的,并保證已經(jīng)是 Proxy。
但是,當使用合成 API 顯式創(chuàng)建響應式對象時,最佳做法是不要保留對原始對象的引用,而只使用響應式版本:
const obj = reactive({
count: 0
}) // no reference to original#偵聽器
每個組件實例都有一個相應的偵聽器實例,該實例將在組件渲染期間把“觸碰”的所有 property 記錄為依賴項。之后,當觸發(fā)依賴項的 setter 時,它會通知偵聽器,從而使得組件重新渲染。
點擊此處實現(xiàn)
將對象作為數(shù)據(jù)傳遞給組件實例時,Vue 會將其轉(zhuǎn)換為 Proxy。這個 Proxy 使 Vue 能夠在 property 被訪問或修改時執(zhí)行依賴項跟蹤和更改通知。每個 property 都被視為一個依賴項。
首次渲染后,組件將跟蹤一組依賴列表——即在渲染過程中被訪問的 property。反過來,組件就成為了其每個 property 的訂閱者。當 Proxy 攔截到 set 操作時,該 property 將通知其所有訂閱的組件重新渲染。
如果你使用的是 Vue2.x 及以下版本,你可能會對這些版本中存在的一些更改檢測警告感興趣,在這里進行更詳細的探討。
當前名稱:創(chuàng)新互聯(lián)VUE3教程:Vue 3.0 響應性 深入響應性原理
分享路徑:http://www.5511xx.com/article/ccdcejc.html


咨詢
建站咨詢
