Vue渲染器的簡(jiǎn)單模擬實(shí)現(xiàn)(vnode生成、掛載秉扑、patch)

Vue渲染器的簡(jiǎn)單實(shí)現(xiàn)過(guò)程需要做到的幾點(diǎn)是:

1.生成vnode慧邮;

2.把vnode掛載到真實(shí)的dom上面;

3.vnode之間進(jìn)行patch舟陆,并掛載到真實(shí)dom误澳;

1.生成vnode

vnode本質(zhì)是一個(gè)js對(duì)象,對(duì)象中有非常多的屬性描述節(jié)點(diǎn)秦躯,vue源碼中創(chuàng)建的vnode屬性非常多忆谓,但是在簡(jiǎn)單模擬中,我只選取其中最為重要的三個(gè)屬性tag(節(jié)點(diǎn)類型),props(包裹了事件監(jiān)聽函數(shù)踱承、樣式相關(guān)的class倡缠、style等屬性),children(子節(jié)點(diǎn))進(jìn)行模擬哨免。

要生成vnode,需要定義h函數(shù)昙沦,該函數(shù)接收上述屬性作為參數(shù)琢唾,再包裹為對(duì)象返回回來(lái)從而得到vnode。

2.掛載

定義一個(gè)mount函數(shù)桅滋,將生成的vnode作為參數(shù)傳進(jìn)去的同時(shí)慧耍,vnode掛載到哪里去呢?需要指定對(duì)應(yīng)的容器一起傳入丐谋。

創(chuàng)建對(duì)應(yīng)tag的真實(shí)的element芍碧,處理虛擬節(jié)點(diǎn)的props(暫時(shí)只考慮界節(jié)點(diǎn)的事件監(jiān)聽和其他不需要做額外處理的屬性),處理節(jié)點(diǎn)為文本類型(children為string)的情況号俐,并掛載到傳入的容器

在頁(yè)面掛載一個(gè)試一試

文本類型順利掛載之后泌豆,假如節(jié)點(diǎn)有他的子節(jié)點(diǎn)呢,那么遍歷子節(jié)點(diǎn)吏饿,并調(diào)用mount函數(shù)掛載到該節(jié)點(diǎn)上(相當(dāng)于一個(gè)遞歸操作)

傳入子節(jié)點(diǎn)試試:

基本上踪危,掛載功能實(shí)現(xiàn)了,下一步是視圖發(fā)生變化猪落,vnode之間patch的實(shí)現(xiàn)

3.vnode之間的patch

首先贞远,判斷兩個(gè)vnode之間是不是相同的類型,如果不是相同的類型笨忌,簡(jiǎn)單粗暴的將之前的el卸載掉蓝仲,掛載新的。

如果vnode是相同類型:

取出el對(duì)象官疲,并處理所有props(新的props就加上负敏,舊的就刪掉)

處理children:假如新children是string袜茧,給到el(也可以說(shuō)是替換)桐愉;如果新children是數(shù)組而克,再去判斷舊children是string還是數(shù)組,

舊children是string:將文本清空维费,將新children遍歷掛載到el果元;舊children是數(shù)組,進(jìn)行patch犀盟。

children之間的pacth操作就是源碼中沒有key的patch噪漾,感興趣可以查看我的patch過(guò)程中有無(wú)key屬性的相關(guān)源碼梳理

模擬一下:

效果:


patch函數(shù)代碼如下:

const patch = (n1, n2) => {

? // 先判斷類型tag是否一樣

? if (n1.tag !== n2.tag) {

? ? const n1ElParent = n1.el.parentElement

? ? n1ElParent.removeChild(n1.el)

? ? mount(n2, n1ElParent)

? } else {

? ? // 1.取出element對(duì)象,并且在n2中進(jìn)行 保存

? ? const el = n2.el = n1.el

? ? // 2.處理props

? ? const oldProps = n1.props || {}

? ? const newProps = n2.props || {}

? ? // 2.1獲取所有newprops 添加到el

? ? for (const key in newProps) {

? ? ? const oldValue = oldProps[key]

? ? ? const newValue = newProps[key]

? ? ? if (newValue !== oldValue) {

? ? ? ? if (key.startsWith('on')) { // 對(duì)事件監(jiān)聽的判斷

? ? ? ? ? el.addEventListener(key.slice(2).toLowerCase(), newValue)

? ? ? ? } else {

? ? ? ? ? el.setAttribute(key, newValue)

? ? ? ? }

? ? ? }

? ? }

? ? // 2.2刪除舊的props

? ? for (const key in oldProps) {

? ? ? if (!(key in newProps)) {

? ? ? ? const value = oldProps[key]

? ? ? ? if (key.startsWith('on')) { // 對(duì)事件監(jiān)聽的判斷

? ? ? ? ? el.removeEventListener(key.slice(2).toLowerCase(), value)

? ? ? ? } else {

? ? ? ? ? el.removeAttribute(key)

? ? ? ? }

? ? ? }

? ? }

? ? // 3.處理children

? ? const oldChildren = n1.children || []

? ? const newChildren = n2.children || []

? ? if (typeof newChildren === 'string') { // 情況1: newChildren本身是string

? ? ? if (typeof oldChildren === 'string') {

? ? ? ? if (oldChildren !== newChildren) {

? ? ? ? ? el.textContent = newChildren

? ? ? ? }

? ? ? } else {

? ? ? ? el.innerHTML = newChildren

? ? ? }

? ? } else { // 情況2:newChildren本身是數(shù)組

? ? ? if (typeof oldChildren === 'string') {

? ? ? ? el.innerHTML = ''

? ? ? ? newChildren.forEach(item => {

? ? ? ? ? mount(item, el)

? ? ? ? })

? ? ? } else {

? ? ? ? // oldChildren: [v1, v2, v3, v6]

? ? ? ? // newChildren: [v1, v5, v6, v8, v9]

? ? ? ? // 1.前面又相同節(jié)點(diǎn)的元素進(jìn)行patch操作

? ? ? ? const commonLength = Math.min(oldChildren.length, newChildren.length)

? ? ? ? for (let i = 0; i<commonLength; i++) {

? ? ? ? ? patch(oldChildren[i], newChildren[i])

? ? ? ? }

? ? ? ? // 2.newChildren.length > oldChildren.length

? ? ? ? if(newChildren.length > oldChildren.length) {

? ? ? ? ? newChildren.slice(oldChildren.length).forEach(item=>{

? ? ? ? ? ? mount(item,el)

? ? ? ? ? })

? ? ? ? }

? ? ? ? // 3.newChildren.length < oldChildren.length

? ? ? ? if(newChildren.length < oldChildren.length) {

? ? ? ? ? oldChildren.slice(newChildren.length).forEach(item=>{

? ? ? ? ? ? console.log(item.el)

? ? ? ? ? ? el.removeChild(item.el)

? ? ? ? ? })

? ? ? ? }

? ? ? }

? ? }

? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末且蓬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子题翰,更是在濱河造成了極大的恐慌恶阴,老刑警劉巖诈胜,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異冯事,居然都是意外死亡焦匈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門昵仅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缓熟,“玉大人,你說(shuō)我怎么就攤上這事摔笤」换” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵吕世,是天一觀的道長(zhǎng)彰触。 經(jīng)常有香客問(wèn)我,道長(zhǎng)命辖,這世上最難降的妖魔是什么况毅? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮尔艇,結(jié)果婚禮上尔许,老公的妹妹穿的比我還像新娘。我一直安慰自己终娃,他們只是感情好味廊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尝抖,像睡著了一般毡们。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昧辽,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天衙熔,我揣著相機(jī)與錄音,去河邊找鬼搅荞。 笑死红氯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咕痛。 我是一名探鬼主播痢甘,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼茉贡!你這毒婦竟也來(lái)了塞栅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤腔丧,失蹤者是張志新(化名)和其女友劉穎放椰,沒想到半個(gè)月后作烟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砾医,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拿撩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片如蚜。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡压恒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出错邦,到底是詐尸還是另有隱情探赫,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布兴猩,位于F島的核電站期吓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏倾芝。R本人自食惡果不足惜讨勤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晨另。 院中可真熱鬧潭千,春花似錦、人聲如沸借尿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)路翻。三九已至狈癞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茂契,已是汗流浹背蝶桶。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掉冶,地道東北人真竖。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像厌小,于是被迫代替她去往敵國(guó)和親恢共。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容