Vue源碼分析(一) : new Vue() 作了什麼
author: @TiffanysBearjavascript
在瞭解new Vue作了什麼以前,咱們先對Vue源碼作一些基礎的瞭解,若是你已經對基礎的源碼目錄設計等有基礎的瞭解的話,能夠跳過下面這部分。vue
Vue.js 的源碼都在 src 目錄下,其目錄結構以下。java
src
├── compiler # 編譯相關
├── core # 核心代碼
├── platforms # 不一樣平臺的支持
├── server # 服務端渲染
├── sfc # .vue 文件解析
├── shared # 共享代碼
複製代碼
compiler 目錄包含 Vue.js 全部編譯相關的代碼。它包括把模板解析成 AST 語法樹,AST語法樹優化,代碼生成等功能。react
編譯的工做能夠在構建時作(能夠藉助 webpack、vue-loader 等插件);也能夠在運行時作,使用包含構建功能的 Vue.js。編譯是一項耗性能的工做,因此更推薦前者——離線編譯。webpack
core 目錄包含了 Vue.js 的核心代碼,包括有內置組件、全局 API 封裝,Vue 實例化、Obsever、Virtual DOM、工具函數 Util 等等。git
Vue.js 是一個跨平臺的 MVVM 框架,它能夠跑在 web 上,也能夠配合 weex 跑在 native 客戶端上。platform 是 Vue.js 的入口,2 個目錄表明 2 個主要入口,分別打包成運行在 web 上和 weex 上的 Vue.js。github
Vue.js 2.0 支持了服務端渲染,全部服務端渲染相關的邏輯都在這個目錄下。注意:這部分代碼是跑在服務端的 Node.js,不要和跑在瀏覽器端的 Vue.js 混爲一談。web
服務端渲染主要的工做是把組件渲染爲服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最後將靜態標記"混合"爲客戶端上徹底交互的應用程序。編程
一般咱們開發 Vue.js 都會藉助 webpack 構建, 而後經過 .vue 單文件來編寫組件。json
這個目錄下的代碼邏輯會把 .vue 文件內容解析成一個 JavaScript 的對象。
Vue.js 會定義一些工具方法,這裏定義的工具方法都是會被瀏覽器端的 Vue.js 和服務端的 Vue.js 所共享的。
接下來咱們來找一下Vue的入口文件,咱們接下來的分析都是基於platform爲web的環境下進行的分析,從 package.json 和 config的 的打包配置中裏能夠看出,運行在web環境 (Runtime only (CommonJS))
的入口文件在 web/entry-runtime.js
下。
Vue入口文件目錄 vue/src/core/instance/index.js
// vue/src/core/instance/index.js
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
複製代碼
採用的是ES5的寫法,並非ES6的Class寫法的優勢,是由於:
一、使用混入Mixin的方式傳入Vue,爲Vue的原型prototype上增長方法。class難以實現這種方法 二、此種方式將代碼模塊合理劃分,將擴展分散到多個模塊中去實現,使得代碼文件不會過於龐大,便於維護和管理。這個編程技巧之後能夠用於代碼開發實現中。
經過Mixin增長的原型方法:
// vue/src/core/instance/index.js
initMixin(Vue) // _init
stateMixin(Vue) // $set、$delete、$watch
eventsMixin(Vue) // $on、$once、$off、$emit
lifecycleMixin(Vue) // _update、$forceUpdate、$destroy、
renderMixin(Vue) // $nextTick、_render
複製代碼
在 vue/src/core/index.js 中,調用的initGlobalAPI(Vue),是爲Vue增長靜態方法的,
在路徑 vue/src/core/global-api/ 目錄下的文件中,都是給Vue添加的靜態方法
好比:
Vue.use // 使用plugin
Vue.extend
Vue.mixin
Vue.component
Vue.directive
Vue.filter
複製代碼
有了這些基礎的瞭解和一步步的跟蹤查找後,咱們一步一步找到了 new Vue
所在的位置,接下來咱們來看下 new Vue
到底作了什麼?
從入口的文件看來,經過new關鍵字初始化,調用了
// src/core/instance/index.js
this._init(options)
複製代碼
而後從Mixin增長的原型方法看,initMixin(Vue),調用的是爲Vue增長的原型方法_init
// src/core/instance/init.js
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
....
....
// expose real self
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
....
....
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
複製代碼
因此,從上面的函數看來,new vue所作的事情,就像一個流程圖同樣展開了,分別是
beforeCreate
鉤子函數$watch
變成reactivity,可是 $el
仍是沒有生成,也就是DOM沒有生成)在初始化的最後,檢測到若是有 el 屬性,則調用 vm.$mount 方法掛載 vm,掛載的目標就是把模板渲染成最終的 DOM。
Vue代碼初始化的主線邏輯很是分明,使得邏輯和流程很是清楚,這種編程方法值得學習。
如今的部分只是粗略的函數上講了 new Vue
的過程和含義,接下來的文檔會繼續對Vue的源碼進行學習和分析,會接着更細地分析在生命週期lifecyle下每個函數後面具體所作的事情。