專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項(xiàng)目專欄,硬核??推薦??
歡迎各位ITer關(guān)注點(diǎn)贊收藏??????
背景
以下是柏成根據(jù)Vue3官方課程整理的響應(yīng)式書面文檔 - 第一節(jié),課程鏈接在此:Vue 3 Reactivity - Vue 3 Reactivity | Vue Mastery,本文檔可作為課程的輔助材料,配合食用,快樂雙倍!
我們先來看一下這個簡單的Vue應(yīng)用程序,Ok!如果我們加載了這個組件,然后我們的價格price
發(fā)生了改變,Vue是如何知道更新模版內(nèi)容的呢?接下來,我們將會用 Vue3 建造響應(yīng)式的方法,從頭開始制造一個響應(yīng)式引擎,讓我們一步一步的來解決這個問題!
dep
How can we save the total calculation, so we can run it agine when price or quantity updates ?
如何存儲 total 的計(jì)算方式,當(dāng) price 或 quantities 更新時,total 再計(jì)算一次?
我們想將下面這段代碼存儲在某種儲藏室中,然后我們需要運(yùn)行它,之后我們還想再次運(yùn)行這個被存儲的代碼【被存儲可能有多種功能代碼】
let total = price * quantity
讓我們來實(shí)現(xiàn)一下,下面所列舉的effect()
、 track()
、 trigger()
你都可以在 Vue3 響應(yīng)性源碼中看到同名的函數(shù)。
-
dep:一個 Set 對象,存儲我們的
effects
,或者說是一個effect
集(Set)。我們在這里使用 Set 的原因是 Set 不允許出現(xiàn)重復(fù)值,當(dāng)我們嘗試添加同樣的effect
時,它不會變成 Set 集合的兩個子成員 - effect():一個方法,包含了我們想要存儲的代碼
-
track():一個方法,使用
dep
變量去保存effect
-
trigger():一個方法,遍歷
dep
去運(yùn)行我們存儲的所有代碼
depsMap
Often our objects will have multiple properties and each property will need their own dep. How can we store these ?
通常,我們的對象會有多個屬性,每個屬性都需要自己的 Dep(依賴關(guān)系),或者說 effect 的 Set 集合,那么,我們?nèi)绾未鎯Γ蛘哒f怎樣才能讓每個屬性都擁有自己的依賴呢?
我們現(xiàn)在擁有一個product
對象,其每一個屬性都需要有自己的dep
。【dep
其實(shí)就是一個effect
集(Set),這個 effect
集應(yīng)該在值發(fā)生改變時重新運(yùn)行?!?/p>
正如我們看到的,dep
的類型是 Set,Set 中的每個值都只是一個我們需要執(zhí)行的effect
,就像我們這個計(jì)算total
的匿名函數(shù)。要把這些dep
存儲起來,且方便我們以后在找到他們,我們要創(chuàng)建一個depsMap
-
depsMap: 一個 Map 對象,存儲了每個屬性到其自己依賴
dep
對象的映射;每一個屬性都擁有它們自己的,可以重新運(yùn)行effect
的dep
;我們使用對象屬性名作為鍵,比如price
和quantity
,值是一個dep
【effect
集】
讓我們來實(shí)現(xiàn)一下,代碼如下:
<html>
<head></head>
<body>
<div id="app">
<div>depsMap</div>
</div>
</body>
<script>
const depsMap = new Map()
// Save this code
function track(key) {
let dep = depsMap.get(key) // Get the dep for this property
if (!dep) {
depsMap.set(key, (dep = new Set())) // No dep yet, so let's create one
}
dep.add(effect) // Add this effect Since it's a set, it won't add the effect again if it already exists
}
// Run all the code I've saved
function trigger(key) {
let dep = depsMap.get(key) // Get the dep for the key
if (dep) {
dep.forEach(effect => {
effect() // If it exists, run each effect
})
}
}
let product = {
price: 5,
quantity: 2,
}
let total = 0
let effect = () => {
total = product.price * product.quantity
}
track('quantity')
effect()
</script>
</html>
當(dāng)我們觸發(fā)函數(shù)trigger('quantity')
, effect
就運(yùn)行了;控制臺輸出結(jié)果如下:
現(xiàn)在我們就對 對象中的不同屬性 有了一種跟蹤依賴關(guān)系的方法
targetMap
What if we have multiple reactive objects that each need to track effects ?
如果我們有多個響應(yīng)式對象,每個響應(yīng)式對象屬性都需要存儲 effect 呢?例如?
let product = { price: 5, quantity: 2 }
let user = { name: "burc", age: 18 }
到目前為止,我們有一張 depsMap,它存儲了每個屬性自己的依賴對象(屬性到自己依賴對象的映射)。然后每個屬性都擁有它們自己的并可以重新運(yùn)行effect
的dep
。
我們這里需要一個其他對象,即 targetMap 。它的鍵以某種方式引用了我們的響應(yīng)性對象,例如product
或user
- targetMap: 一個 WeakMap 對象,它儲存了與每個 響應(yīng)性對象屬性 關(guān)聯(lián)的依賴,在 Vue3 中,它被稱為目標(biāo)圖
-
WeakMap: 與 Map 結(jié)構(gòu)類似,但只接受對象作為鍵名(
null
除外),不接受其他類型的值作為鍵名
用一個簡單的例子告訴我們 WeakMap 是如何工作的,如想了解詳細(xì)API請移步 阮一峰ES6文檔-WeakMap
let product = { price: 5, quantity: 2 }
const targetMap = new WeakMap()
targetMap.set(product, "example code to test")
console.log(targetMap.get(product))
//"example code to test"
讓我們來實(shí)現(xiàn)一下,代碼如下:
<html>
<head></head>
<body>
<div id="app">
<div>targetMap</div>
</div>
</body>
<script>
const targetMap = new WeakMap() // For storing the dependencies for each reactive object
// Save this code
function track(target, key) {
let depsMap = targetMap.get(target) // Get the current depsMap for this target(reactive object - product)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map())) // If it doesn't exist, create it
}
let dep = depsMap.get(key) // Get the dependency object for this peoperty - quantity
if (!dep) {
depsMap.set(key, (dep = new Set())) // If it doesn't exist, create it
}
dep.add(effect) // Add the effect to the dependency
}
// Run all the code I've saved
function trigger(target, key) {
const depsMap = targetMap.get(target) // Does this object have any properties that have dependencies?
if (!depsMap) {
return // If no, return from the function immediately
}
let dep = depsMap.get(key) // Otherwise, check if this property has a dependency
if (dep) {
dep.forEach(effect => {
effect()
}) // Run those
}
}
let product = { price: 5, quantity: 2 }
let total = 0
let effect = () => {
total = product.price * product.quantity
}
track(product, 'quantity')
effect()
</script>
</html>
當(dāng)我們觸發(fā)函數(shù) trigger(product, 'quantity')
,effect
就運(yùn)行了;控制臺輸出結(jié)果如下:
diagram
讓我們再分析概括一下圖表
- targetMap:存儲了每個 響應(yīng)性對象屬性 關(guān)聯(lián)的依賴;類型是 WeakMap
- depsMap:存儲了每個屬性的依賴;類型是 Map
-
dep:存儲了我們的
effects
,一個effects
集,這些effect
在值發(fā)生變化時重新運(yùn)行;類型是 Set
文章來源:http://www.zghlxwxcb.cn/news/detail-710861.html
Now!我們就實(shí)現(xiàn)了一種儲存不同effect
的方法,但是我們還沒有辦法讓我們的effect
自動重新運(yùn)行。這是第二個重要的部分,將在下一篇文章講解!文章來源地址http://www.zghlxwxcb.cn/news/detail-710861.html
到了這里,關(guān)于【Vue3響應(yīng)式入門#01】Reactivity的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!