Vue核心概念
- vue實(shí)例化
- 虛擬dom
- 模板編譯
- 數(shù)據(jù)綁定(響應(yīng)式)
- 組件化
MVVM
model和view層通過中間的vm連接和驅(qū)動(dòng)憔晒。model層數(shù)據(jù)變化會(huì)改變視圖甚侣,view改變通過事件來修改數(shù)據(jù)明吩。vue參考了MVVM實(shí)現(xiàn)了雙向綁定,react是MVC; 但是vue仍然可以通過refs/parent等操作dom,所以不全是mvvm
vue模板解析
- 1殷费、先將代碼轉(zhuǎn)換為AST樹
根據(jù)正則匹配印荔,從第一個(gè)字符開始,篩選過的就刪掉繼續(xù)index++向后匹配详羡。
如果匹配開始標(biāo)簽就放入一個(gè)stack中仍律,此時(shí)如果匹配到結(jié)束標(biāo)簽則出棧對(duì)比是否一致,不一致報(bào)錯(cuò) - 2实柠、優(yōu)化AST樹
找出靜態(tài)節(jié)點(diǎn)并標(biāo)記水泉,之后就不需要diff了
遞歸遍歷ast樹中的節(jié)點(diǎn),如果沒有表達(dá)式、v-if草则、v-for等钢拧,就標(biāo)記static為true - 3、生成render函數(shù)畔师、在使用new Function(with() {})包裹
轉(zhuǎn)換成render函數(shù)娶靡。編譯結(jié)束。一定要包裹new Function和with來更改上下文環(huán)境
v-if解析出來就是三元表達(dá)式看锉,v-for解析出來_l((3),..) - 4姿锭、render函數(shù)執(zhí)行后得到的是虛擬dom;AST是需要吧代碼使用正則匹配生成的伯铣,然后轉(zhuǎn)換成render呻此,而虛擬dom則是通過render函數(shù)直接生成一個(gè)對(duì)象
虛擬dom
VDom:三部曲
用 JavaScript 對(duì)象模擬真實(shí) DOM 樹,對(duì)真實(shí) DOM 進(jìn)行抽象腔寡;
diff 算法 — 比較兩棵虛擬 DOM 樹的差異焚鲜;
patch 算法 — 將兩個(gè)虛擬 DOM 對(duì)象的差異應(yīng)用到真正的 DOM 樹。
可以查看本文作者寫的另一篇詳解虛擬 DOM 的文章《深入剖析:Vue核心之虛擬DOM》https://juejin.cn/post/6844903895467032589#heading-14
vue的雙向數(shù)據(jù)綁定放前、響應(yīng)式原理
響應(yīng)式設(shè)計(jì)重要的三個(gè)對(duì)象忿磅;
- 監(jiān)聽器 Observer ,用來劫持并監(jiān)聽所有屬性(轉(zhuǎn)變成setter/getter形式)凭语,如果屬性發(fā)生變化葱她,就通知訂閱者(watcher)
- 訂閱器 Dep,用來收集訂閱者(Watcher)似扔,對(duì)監(jiān)聽器 Observer和訂閱者 Watcher進(jìn)行統(tǒng)一管理吨些,每一個(gè)屬性數(shù)據(jù)都有一個(gè)dep記錄保存訂閱他的watcher。
- 訂閱者 Watcher炒辉,可以收到屬性的變化通知并執(zhí)行相應(yīng)的方法豪墅,從而更新視圖,每個(gè)watcher上都會(huì)保存對(duì)應(yīng)的dep黔寇;(將模板和Observer對(duì)象結(jié)合生成實(shí)例)
- 解析器 Compile偶器,可以解析每個(gè)節(jié)點(diǎn)的相關(guān)指令,對(duì)模板數(shù)據(jù)和訂閱器進(jìn)行初始化
如何亮點(diǎn)解答缝裤?状囱?
1、在生命周期的initState方法中將data倘是,prop,method袭艺,computed搀崭,watch中的數(shù)據(jù)劫持, 通過observe方法與Object.defineProperty方法將相關(guān)對(duì)象轉(zhuǎn)為換Observer對(duì)象。
2瘤睹、然后在initRender方法中解析模板升敲,通過Watcher對(duì)象,Dep對(duì)象與觀察者模式將模板中的 指令與對(duì)象的數(shù)據(jù)建立依賴關(guān)系轰传,使用全局對(duì)象Dep.target實(shí)現(xiàn)依賴收集驴党。
3、當(dāng)數(shù)據(jù)變化時(shí)获茬,setter被調(diào)用港庄,觸發(fā)Object.defineProperty方法中的dep.notify方法, 遍歷該數(shù)據(jù)依賴列表恕曲,執(zhí)行器update方法通知Watcher進(jìn)行視圖更新(微任務(wù)異步更新)鹏氧。
vue是無法檢測(cè)到對(duì)象屬性的添加和刪除,但是可以使用全局Vue.set方法(或vm.$set實(shí)例方法)佩谣。
vue無法檢測(cè)利用索引設(shè)置數(shù)組把还,但是可以使用全局Vue.set方法(或vm.$set實(shí)例方法)。
無法檢測(cè)直接修改數(shù)組長(zhǎng)度茸俭,但是可以使用splice吊履;
再去結(jié)合vue3做的相關(guān)優(yōu)化,闡述调鬓;
Object.defineProperty艇炎?
- 必須預(yù)先知道要攔截的 key 是什么,所以它并不能檢測(cè)對(duì)象屬性的添加和刪除袖迎。盡管 Vue.js 為了解決這個(gè)問題提供
delete 實(shí)例方法冕臭,但是對(duì)于用戶來說,還是增加了一定的心智負(fù)擔(dān)燕锥。
- Vue.js 無法判斷你在運(yùn)行時(shí)到底會(huì)訪問到哪個(gè)屬性辜贵,所以對(duì)于這樣一個(gè)嵌套層級(jí)較深的對(duì)象,如果要劫持它內(nèi)部深層次的對(duì)象變化归形,就需要遞歸遍歷這個(gè)對(duì)象托慨,執(zhí)行 Object.defineProperty 把每一層對(duì)象數(shù)據(jù)都變成響應(yīng)式的。毫無疑問暇榴,如果我們定義的響應(yīng)式數(shù)據(jù)過于復(fù)雜厚棵,這就會(huì)有相當(dāng)大的性能負(fù)擔(dān)。
- 數(shù)組實(shí)現(xiàn)響應(yīng)式
Proxy(數(shù)據(jù)劫持優(yōu)化)
- 劫持的是整個(gè)對(duì)象蔼紧,那么自然對(duì)于對(duì)象的屬性的增加和刪除都能檢測(cè)到
- 注意的是 Proxy API 并不能監(jiān)聽到內(nèi)部深層次的對(duì)象變化婆硬,因此 Vue.js 3.0 的處理方式是在 getter 中去遞歸響應(yīng)式,這樣的好處是真正訪問到的內(nèi)部對(duì)象才會(huì)變成響應(yīng)式奸例,而不是無腦遞歸彬犯,這樣無疑也在很大程度上提升了性能
區(qū)別:
1向楼、語法層面上
defineProperty只能響應(yīng)首次渲染時(shí)候的屬性,
Proxy需要的是整體監(jiān)聽谐区,不需要關(guān)心里面有什么屬性湖蜕,而且Proxy的配置項(xiàng)有13種,可以做更細(xì)致的事情宋列,這是之前的defineProperty無法達(dá)到的昭抒。
2、兼容層面上
vue2.x之所以只能兼容到IE8就是因?yàn)閐efineProperty無法兼容IE8,其他瀏覽器也會(huì)存在輕微兼容問題炼杖。
proxy的話除了IE灭返,其他瀏覽器都兼容,這次vue3還是使用了它嘹叫,說明vue3直接放棄了IE的兼容考慮婆殿。
數(shù)據(jù)發(fā)生變化后,dom是怎么更新的罩扇?流程婆芦? === watcher.update怎么樣更新視圖? 將watcher放入一個(gè)更新隊(duì)列里喂饥。
待解答消约、、patch员帮、diff
https://juejin.cn/post/6947514223169798175#heading-1