個人自學前端28-Vue5-虛擬節點,生命週期
一. 虛擬節點
目前流行的檢視框架都是基於虛擬節點技術開發的.
檢視框架 => 更新檢視的最後非同步是DOM操作. => 儘量以最低的代價進行DOM操作.
檢視框架如何進行最低代價的DOM操作 => 虛擬節點 => 虛擬節點的更新 => diff演算法.
虛擬節點 => 一個純物件 => 描述真實節點.
虛擬節點在描述一個標籤時,都有3個最基本的屬性 => 標籤名,屬性列表,子節點列表。
虛擬節點就是真實節點的js描述.(AST語法樹)
const Vnode = {
// 描述標籤名
tag: 'div',
// 描述屬性節點列表
attrs: [{id: 'app'}],
children: [{
tag: 'h3',
attrs: [],
children: ['Vue你好']
}]
}
console.log(vm._vnode);
真實節點更新 => 一定是DOM操作完成.
虛擬節點更新 => 修改純物件.
如何根據更新後的虛擬節點,決定如何進行DOM操作去更新真實節點. => diff演算法.
diff演算法 => 比較更新前和更新後的虛擬節點一桶,最終決定如何進行DOM操作.
二. 生命週期
Vue的生命週期 => Vue例項從建立達到銷燬過程中的特定階段.
new Vue例項化(元件例項化)
觸發beforeCreate
通過Object.defineProperty給data資料設定資料劫持
觸發created.
判斷有沒有el選項.
如果沒有el選項,則等待$mount方法觸發,如果這個方法也沒觸發,則例項化失敗.( $mount(選擇器) === el: 選擇器)
如果有,繼續判斷有沒有template選項
如果有template選項,則編譯template
如果沒有template選項,則編譯el所在的標籤
觸發beforeMount
根據編譯的虛擬節點生成真實節點vm.$el.並且用真實的新檢視替換掉老檢視
觸發mounted.進入執行階段.
監控資料變化,觸發beforeUpdate,updated
例項(元件DOM)銷燬時,先呼叫beforeDestory
呼叫Destroyed,全部銷燬
1. 建立期
建立 => 給vue例項新增資料 => 給data設定資料劫持.
建立前後 => 資料劫持前後.(Object.defineProperty進行資料劫持前後)
這兩個鉤子只會觸發一次.
- beforeCreate
建立前 => 沒什麼用 - created
建立後 => 一般用於資料初始化。
在這個建構函式內只能操作資料,不能操作檢視.
2. 掛載期
掛載 => 新檢視替換老檢視.(元件template替換元件標籤).
掛載前後 => 新檢視出現前後.
這兩個鉤子也只觸發一次.
mounted => 檢視初始化.
掛載都發生了什麼事情?
- 編譯template.(把字串模板編譯成虛擬節點).
- 編譯遇到指令和插值表示式,都會進行求值.(收集依賴).
- 把虛擬節點轉換為新檢視,替換老檢視.
3. 更新期
檢視更新前後 => 分別觸發beforeUpdate和updated
預設不觸發(Vue例項化階段不觸發).
Vue例項化完成之後,檢視再更新,才會觸發.
有可能觸發很多次.
- updated和watch的區別
updated => 檢視更新就觸發.不能知道本次更新是由於哪個資料變化導致的.具有響應式效果的資料變化,都觸發updated.
watch => 資料變化就觸發.監聽哪個資料,就觸發哪個方法. - 更新真實節點
資料變化 => 導致檢視更新 (響應式)
資料變化 => 先更新虛擬節點 => diff演算法判斷 => 最後更新真實節點。- 原地更新.(標籤不增刪,不移動,直接修改內容或者屬性)(更新前後是同一個標籤) => 更新前後的tag和key完全一致.
- 替換更新.(會增刪,移動元素)(新增,刪除,移動) => tag或key有一個不一樣.
- 什麼時候原地更新?什麼時候替換更新?
- 比較更新前後的虛擬節點.(同級比較)
- 如果同級的tag一致,並且key一樣,則表示更新前後是同一個標籤,使用原地更新策略.
- 如果同級的tag或者key有一個不一樣,則表示更新前後不是同一個標籤,使用替換更新策略.
4. 銷燬期
destroyed => 元件銷燬後的善後處理,例如停止定時器
元件銷燬只是讓資料不驅動檢視更新了而已.元件例項還是存在的.
5.父子元件生命週期順序
父beforeCreate
父created
父beforeMount
子beforeCreate
子created
子beforeMount
子mounted
父mounted
為什麼順序是這樣的. => 函式執行順序回答.父元件的檢視編譯就是一個函式從上往下執行.
能不能修改這個順序.(4父4子) => 通過v-if實現.父元件掛載後再編譯子元件.
三. nextTick
如何針對某個資料變化導致的檢視更新寫單獨的邏輯?
vue的檢視更新是非同步的,資料變化不會馬上導致檢視更新.
nextTick的回撥函式,會在檢視更新後自動觸發.只觸發一次
一定是用來處理跟檢視相關的邏輯.
const App = {
template: `
<div>
<button @click='fn'>修改str</button>
<ul ref='ul'>
<li v-for='d in count'>{{d}}</li>
</ul>
</div>
`,
data() {
return {
count: 0
}
},
methods: {
fn() {
// 資料變化會導致檢視變化.檢視變化完成之後,就會觸發nextTick
this.count++;
// 這裡只會在count變化導致的檢視更新後觸發.
this.$nextTick(() => {
let oUl = this.$refs.ul;
oUl.scrollTop = oUl.scrollHeight - oUl.clientHeight;
});
}
}
}