$mount
這一節看掛載,從有編譯的運行時觸發的$mount方法出發,這個函數裏面只有一句話:
el = el && query(el)
這是用來保證el的類型的,我們來看query方法,實現的很直接,如果el是個字符串,使用querySelector拿到DOM節點,沒有這個節點的話,生產環境會報錯;否則返回createElement創建的DOM節點。
如果不是字符串,直接返回el即可。
接着,返回的el不可以是body或者document,這樣直接覆蓋是會破壞HTML結構,因此,這裏做了個判斷+警告。
然後拿到options對象之後,會查看是否有render方法,沒有的話接着看是否有template模板,有的話會做處理,沒有的話會用outerHTML拿到:
最終,template其實是整個我們要掛載的DOM字符串。
如果有render的話就直接render,否則就render剛剛生成的template字符串。這一塊再編譯的時候再具體展開。
接着便走到了之前緩存的mount的方法那裏(之前我們重寫了這個方法),這裏轉到了runtime/index.js裏面。
又一個$mount
這裏調用的是mountComponent方法,定義在instance/lifecycle裏面,其中對傳來的el做了緩存之後,繼續去判斷上一步是不是完成了render,沒有的話就去調用createEmptyVnode創建一個空的VNode。
這裏常見的一個警告就是如果我們使用了沒有compile的runtime版本,在這裏顯然有可能會創建空的VNode,這時就會有各種警告:
'You are using the runtime-only build of Vue where the template '
'compiler is not available. Either pre-compile the templates into '
'render functions, or use the compiler-included build.',
歸根結底還是沒能生成正確的render函數。
接着會有一些方便埋點的操作和一些生命週期的內容,這裏也先不展開。
最終這裏定義了一個函數:
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
這裏的hydrating我們可以忽略,是服務端渲染的內容,暫時認爲是false即可。前者是通過vm._render渲染的VNode。
接着下面通過new了一個Watcher,裏面使用到了updateComponent函數,這裏的watcher可以看作是個渲染watcher,這裏就要轉到watcher類裏去看看這個和響應式強相關的重要函數。
所謂的render watcher其實就給vm綁定一個_watcher屬性。
if (isRenderWatcher) {
vm._watcher = this
}
vm._watchers.push(this)
接着很多內容我們先忽略,只需指定再get裏面去call(vm, vm)時即執行剛剛定義的updateComponent函數,自然就執行了vm._update和vm._render兩個函數,當然後者先執行,前者再執行,這裏涉及VNode的內容,下次繼續。
最後提一句爲什麼總要watcher裏面去執行updateComponent,相比大家看到這裏也有感覺了,不僅僅是渲染,我們還需要watch更新,無論如何updateComponent都是必不可少的入口文件,自然需要和watcher強相關。
總結
以後每天讀一部分吧,另外題也要做起來了,越來越覺得數據結構重要了。