mount, 意思爲掛載。能夠理解爲將vue實例(邏輯應用),掛靠在某個dom元素(載體)上的一個過程。html
上一篇文章咱們講到, 在建立一個vue實例的時候(var vm = new Vue(options))。Vue的構造函數將自動運行 this._init(啓動函數)。啓動函數的最後一步爲initRender(vm),vue
// Vue.prototype._init ... initLifecycle(vm); initEvents(vm); callHook(vm, 'beforeCreate'); initState(vm); callHook(vm, 'created'); initRender(vm);
initRender中調用vm.$mount(vm.$options.el),將實例掛載到dom上,至此啓動函數完成。node
//initRender ... if (vm.$options.el) { vm.$mount(vm.$options.el); }
能夠看出,vm.$mount爲vue渲染的主要函數算法
上圖,展現的是獨立構建時的一個渲染流程圖瀏覽器
模板字符串服務器
//模板字符串 <div id = "app"> {{message}} </div>
render函數app
//render函數 function anonymous() { with(this){return _h('div',{attrs:{"id":"app"}},["\n "+_s(message)+"\n"])} }
vnodedom
真實dom節點($el)ide
咱們先看一下官方文檔 獨立構建和運行時構建函數
這兩個概念,我在初學的時候是一頭霧水。如今對照着渲染的流程圖,咱們能夠知道
獨立構建:包含模板編譯器
渲染過程: html字符串 → render函數 → vnode → 真實dom節點
運行時構建: 不包含模板編譯器
渲染過程: render函數 → vnode → 真實dom節點
運行時構建經過砍掉模板編譯器,讓整個包少了30%(官方數據)。我在閱讀源碼的過程當中,發現vue源碼7000餘行,而和模板編譯相關的代碼,則約有1000行左右。看起來確實是輕便了。這是在鼓勵咱們多用render函數嗎?
上面咱們說到,運行時構建的包,會比獨立構建少一個模板編譯器。在$mount函數上也不一樣
運行時構建的 $mount函數
而獨立構建的 $mount函數,會先用一個臨時變量mount保存上面的$mount方法
var mount = Vue$2.prototype.$mount; //此處mount即爲運行時版的 $mount
而後重寫$mount函數,這時,調用$mount就會包括模板編譯功能了
var mount = Vue$2.prototype.$mount; Vue$2.prototype.$mount = function (el, hydrating) { ...省略代碼(裏面爲模板編譯器入口)... return mount.call(this, el, hydrating) };
咱們能夠看到,無論獨立構建仍是運行時構建,都會調用 vm._mount方法咱們來看看源碼
Vue.prototype._mount = function(el, hydrating) { ...一些防止運行時的包,卻用了template的報錯代碼... callHook(vm, 'beforeMount'); vm._watcher = new Watcher(vm, function () { vm._update(vm._render(), hydrating); }, noop); hydrating = false; if (vm.$vnode == null) { vm._isMounted = true; callHook(vm, 'mounted'); } return vm }
使用過的vue的人,都會很敏銳地發現, 在調用beforeMount生命週期,和mounted生命週期中間的關鍵代碼爲
鑑於大牛已經講過不少次這裏的數據監聽了,咱們只講其中渲染部分
vm._update(vm._render(), hydrating);
vm._render函數返回一個vnode做爲 vm._update的參數。 hydrating是與服務器渲染(SSR)相關的,瀏覽器端能夠不用管。
vm._render (將render函數轉化成vnode)
最核心代碼爲
var render = vm.$options.render try{ vnode = render.call(vm._renderProxy, vm.$createElement); }catch{ ... }
此處,使用call方法, 將this指向 vm.renderProxy js功底差的同窗要去補補知識了。
vm.renderProxy是個代理,代理vm,主要用來報錯,若是render函數上使用了vm上沒有的屬性或方法,就會報錯。
vm.$createElement 這個是建立vnode的方法,做爲第一個參數傳入。
render函數
這裏的h便是, vm.$createElement ,即是在vm._render這個階段被傳入。
vm._update (將vnode生成真實dom節點)
最關鍵一句話爲
vm.$el = vm.__patch__(prevVnode, vnode);
vm.__patch__也是個你們夥,我以後會再去研究。
裏面的方法,將新舊vnode使用 diff算法進行比對,找出要替換的地方,這樣更新dom的性能會有較大優化。
最後會返回一個dom節點。
這個時候將vm.$el 賦值爲這個dom節點,掛載完成!