摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理從模板到的簡要流程今天的計(jì)劃是,
寫文章不容易,點(diǎn)個(gè)贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】
如果你覺得排版難看,請點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧
【Vue原理】從模板到DOM的簡要流程
今天的計(jì)劃是,探索Vue模板掛載到頁面是怎么樣的一個(gè)流程,內(nèi)容是指 正常 HTML 標(biāo)簽的模板掛載,這部分內(nèi)容很重要。
而這部分內(nèi)容也是為了 講解 Component 作為鋪墊,因?yàn)榈阶詈?Component 必然也是作為一個(gè)正常標(biāo)簽去掛載,所以先把這部分抽出來講
首先,這個(gè)流程,個(gè)人認(rèn)為可以分為兩大部分,分別是 init 和 mount
顧名思義,init 必定是和初始化有關(guān),mount 和 掛載DOM 有關(guān)
Init首先,當(dāng)你開始調(diào)用 Vue 的時(shí)候,比如這樣
// js new Vue({ el: document.getElementsByTagName("div")[0], }) // html,夠簡潔了吧
那么,先進(jìn)入的肯定是 Vue 這個(gè)構(gòu)造函數(shù),呈上來!
function Vue(options) { this._init(options); } Vue.prototype._init = function(options) { // 初始化 選項(xiàng),computed,data 之類的 // 初始化實(shí)例,給實(shí)例綁定些方法 // 觸發(fā) beforeCreated,created 鉤子 }
這個(gè) _init 方法,是構(gòu)建Vue 實(shí)例的時(shí)候調(diào)用的,而創(chuàng)建Vue 實(shí)例,并非只有通過 new Vue 創(chuàng)建,有可能是 Vue 內(nèi)部創(chuàng)建的,比如 component
所以,才需要提取出一個(gè) init 方法
然后,init 到這里就結(jié)束了,下面就到了另一個(gè)流程 mount
Mountinit 結(jié)束,就開始解析模板啦,生成DOM 啦,掛載DOM 啦 之類的
開始正文,首先,從什么時(shí)候開始?此時(shí)需要亮出 _init 方法,沒錯(cuò),就是上面出現(xiàn)的方法
其實(shí)在這個(gè)方法的最后,有一個(gè)調(diào)用執(zhí)行掛載DOM 的方法,如下
Vue.prototype._init = function(options) { ..... if (vm.$options.el) { vm.$mount(vm.$options.el); } }
可以看到一句代碼,vm.$mount ,沒錯(cuò),就在這里開啟了 DOM 掛載的 里程碑
但是,等等,有限制條件 vm.$options.el,也就是,必須有傳入 el 才會在 最后調(diào)用 掛載DOM
所以,并不是所有的 Vue 實(shí)例新建都會在 init 結(jié)尾調(diào)用 vm.$mount 去掛載DOM,比如 component 兩個(gè)過程就是分開的
我們還是先來看看 vm.$mount 吧
Vue.prototype.$mount = function(el) { return mountComponent(this, query(el)) }; var mount = Vue.prototype.$mount; Vue.prototype.$mount = function(el) { ...解析模板,生成模板渲染函數(shù),保存渲染函數(shù)到 options return mount.call(this, el) }
原樣呈現(xiàn)了,Vue 中有兩個(gè) $mount 函數(shù),第一個(gè)的作用是給第二個(gè) 調(diào)用......如果大家看源碼,不要搞混了喂
其中涉及到一個(gè)函數(shù),mountComponent,速看
function mountComponent(vm, el) { new Watcher(vm, function() { vm._update(vm._render() }) return v } function Watcher(vm, expOrFn) { this.getter = expOrFn; this.get(); } Watcher.prototype.get = function() { value = this.getter(vm); }
上面代碼的作用可以說是,為 Vue 實(shí)例新建監(jiān)聽者 watcher,并設(shè)置一個(gè)更新函數(shù)
而這個(gè)更新函數(shù),會在新建 watcher后 馬上執(zhí)行,就是馬上執(zhí)行了一遍這行代碼
vm._update(vm._render())1、vm._render
這個(gè)函數(shù)的作用是,執(zhí)行之前解析得到的【渲染函數(shù)】,渲染函數(shù)執(zhí)行完會返回一個(gè) 模板對應(yīng)的 【VNode】
vm._render 再把這個(gè) vnode 返回
于是就把這個(gè) vnode,傳給了 vm._update 中當(dāng)做了第一個(gè)參數(shù)
render 函數(shù)的內(nèi)容其實(shí)非常的多,但是這里一筆帶過,只用知道是用來生成Vnode 就好了,具體的內(nèi)容會有具體的文章講解
Vue.prototype._render = function() { vnode = render(); return vnode }2、vm._update
這個(gè)函數(shù)的作用是,對比 vnode,掛載更新DOM
1、如果存在舊 vnode,那么會對比舊 vnode 和 剛傳入的新 vnode,不斷地 patch 得到最小變化單位,從而只更新這部分DOM
2、如果不存在舊 vnode,那么就直接把 vnode 轉(zhuǎn)換為 dom 掛載到頁面
其中,生成DOM 和 掛載DOM 用到的方法是 createElm
方法很簡單,無非就是通過 標(biāo)簽名創(chuàng)建DOM,然后插入到頁面中
function createElm(vnode, parentElm, refElm) { var children = vnode.children; var tag = vnode.tag; vnode.elm = document.createElement(tag); // 不斷遞歸遍歷子節(jié)點(diǎn) createChildren(vnode, children); // 插入DOM 節(jié)點(diǎn) insert(parentElm, vnode.elm, refElm); } function createChildren(vnode, children) { if (Array.isArray(children)) { for (var i = 0; i < children.length; ++i) { createElm(children[i], vnode.elm, null); } } } function insert(parent, elm, ref) { if (parent) { // 如果存在兄弟節(jié)點(diǎn),就查到兄弟前面 if (ref) { // 兄弟節(jié)點(diǎn)的父節(jié)點(diǎn)和 本節(jié)點(diǎn)父節(jié)點(diǎn)相同 if (ref.parentNode === parent) { parent.insertBefore(elm, ref); } } // 如果沒有兄弟節(jié)點(diǎn),就直接查到父節(jié)點(diǎn)最后 else { parent.appendChild(elm); } } }總結(jié)
兩個(gè)過程如下
init1、初始化選項(xiàng)
2、初始化實(shí)例
mount1、解析模板,生成并保存渲染函數(shù)
2、新建 watcher 并立即執(zhí)行更新函數(shù) vm._update(vm._render)
3、vm._render 調(diào)用渲染函數(shù)生成 VNode,傳給 vm._update
4、調(diào)用 vm._update,根據(jù) VNode 生成 DOM 并掛載
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105403.html
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理源碼版之掛載組件由這篇文章從模 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理白話版從模板上使用到掛載到頁面 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理源碼版之綁定標(biāo)簽事件這里的綁定 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...
摘要:頁面這個(gè)實(shí)例,按理就需要解析兩次,但是有緩存之后就不會理清思路也就是說,其實(shí)內(nèi)核就是不過是經(jīng)過了兩波包裝的第一波包裝在中的內(nèi)部函數(shù)中內(nèi)部函數(shù)的作用是合并公共和自定義,但是相關(guān)代碼已經(jīng)省略,另一個(gè)就是執(zhí)行第二波包裝在中,目的是進(jìn)行緩存 寫文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 ...
摘要:表示虛擬節(jié)點(diǎn),為什么叫虛擬節(jié)點(diǎn)呢,因?yàn)椴皇钦娴墓?jié)點(diǎn)。因?yàn)槭菍ο螅还苓€是瀏覽器,都可以統(tǒng)一操作,從而獲得了服務(wù)端渲染原生渲染手寫渲染函數(shù)等能力減少操作。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點(diǎn)擊 下面鏈接 或者 拉到 下...
閱讀 2013·2021-11-23 10:08
閱讀 2348·2021-11-22 15:25
閱讀 3282·2021-11-11 16:55
閱讀 781·2021-11-04 16:05
閱讀 2618·2021-09-10 10:51
閱讀 719·2019-08-29 15:38
閱讀 1593·2019-08-29 14:11
閱讀 3492·2019-08-29 12:42