在$mount函式中,主要是呼叫了mountcomponent函式,而該函式最後主要是呼叫了updatecomponent函式,
上一次我們分析了render函式的功能(主要是利用createelement函式生成vnode),那麼_update函式主要做了什麼
首先,可以看到在'src/core/instance/lifecycle.js'中在vue原型上定義了私有方法_update,在整個函式中,最重要的部分是執執行__patch__函式。在初始換渲染的階段,向__patch__函式中傳入了四個引數值。
然後,看看__patch__函式的功能(主要是將vnode轉換成dom,渲染在檢視中)。patch定義在'src/platforms/wed/runtime/patch.js'中。
可以看到,最終的patch是乙個createpatchfunction函式返回的函式(函式柯里化),同時傳入了兩個引數。nodeops中是一些關於dom node(dom節點)的操作。modules中包含的是基礎模組和平台模組,因為vue可以執行在不同的平台(web或者weex),因此這樣做的好處是不用每次都去考慮不同平台如何處理。
createpatchfunction定義在'src/core/patch.js'中,在該js中,最後返回了乙個patch函式。在該函式中,第乙個引數是dom元素,第二個引數是vnode。
因為vnode和oldvnode都是定義了的,所以前面兩個if不成立,程式進入從第694行的else語句。因為oldvnode是dom節點,所以isrealelement為true。程式進入703行的else語句中,在第708行的if判斷中,因為第二個條件不成立(並不是在ssr環境中),所以該if判斷不成立。進入712行if判斷,因為hydrating為false,因此不執行該if判斷。
程式執行第728行,oldvnode = emptynodeat(oldnode)。這裡為什麼已經是dom元素了,還要轉換為vnode?我認為應該是這個dom元素是原來我們設定的options中el對應的dom節點,但是我們現在要創新新的節點去替換原來的dom節點。所以先轉換為vnode。之後在同一進行操作。
可以看到,emptynodeat()函式的功能是建立乙個新的vnode。因此oldvnode = emptynodeat(oldnode)創新了新的vnode替換,而原來的oldnode(dom節點)可以在該vnode節點的elm元素中訪問到。
回到patch函式中,取到當前的el對應的dom節點和其父節點後,開始利用createelm函式建立新的dom節點。
在createelm()函式中,主要完成的功能是將構建dom子節點插入到父節點中,並且一直迴圈到該節點沒有子節點為止。這個過程createelm()函式和createchildren函式一起完成。
可以看到,在createchildren()函式中,如果該vnode的子節點是矩陣的話,就會呼叫createelm()函式。因此兩個函式是相互呼叫生成dom節點,然後插入到父節點的過程。如果該子節點是最後乙個節點,則直接在dom節點後面插入該文字節點。(比如message
中的message)
最後,回到patch函式中,因為新建了乙個div來渲染檢視,因此應該把原來的就定義的用來掛載的dom節點(一般是個div)刪掉。所以,可以看到,在vue的渲染過程中,會建立新的dom節點替換掉以前的節點,因此我們在初始化的時候不能講節點擊擇掛載在html和body上。
總結例項的私有方法_update主要是呼叫了patch函式,patch函式的主要功能將vnode轉換為dom節點然後渲染在檢視中。因此,為了生成dom節點,還需要判斷vnode是否有子節點,一直遞迴到沒有子節點時。開始建立子節點並插入在父節點中。最後再將原來定義的根節點移除,因為已經重新建立了新的節點替換原來的根節點。
總結原始碼分析的第一部分至第六部分,其實就是以下過程:
首先在new vue之後,對生命週期、事件中心、data、props等進行了初始化。
然後呼叫$mount函式對$el節點進行渲染。渲染的過程中,vue只認render函式,那麼就會先將template轉換為render函式(mountcomponent函式的功能)。
然後呼叫render函式生成vnode。怎麼生成?主要是利用createelement函式,先將vnode的children處理為一維陣列,然後通過判斷tag來生成vnode。
生成vnode之後,就是通過patch函式轉換為dom節點,渲染在檢視上。那麼,怎麼將vnode轉換為dom節點?在vnode中,有個elm用來儲存對應的dom節點,因此不用再額外生成dom(除了文字節點以外)。只是需要不深度遍歷children,將children中的dom節點新增到父節點中。完成dom樹的構建。
Vue 原始碼之 nextTick 解析
最近在看 vue 原始碼,一直很好奇這個 nexttick 怎麼實現。本文涉及微任務和巨集任務,不熟悉的可以看我之前的部落格 在瀏覽器環境中,常見的 macro task 有 settimeout messagechannel postmessage setimmediate。而常見的 micro ...
Vue原始碼解析
原始碼位置 src core vdom patch.js updatechildren 作用 key的主要作用是高效的更新虛擬dom,原始碼中在patch的過程中,會執行patchvnode,patchvode過程中會執行updatechildren方法,會更新兩個新舊的子元素,通過key可以準確的...
Vue之Watcher原始碼解析(1)
上一節最後再次呼叫了mount函式,我發現竟然跳到了7000多行的那個函式,之前我還說因為宣告早了被覆蓋,看來我錯了!就是這個函式 line 7531 vue 3.prototype.mount function el,hydrating 第一步query就不用看了,el此時是乙個dom節點,所以直...