Vue源碼分析(一) : new Vue () 作了什麼

Vue源碼分析(一) : new Vue() 作了什麼
author: @TiffanysBearjavascript

在瞭解new Vue作了什麼以前,咱們先對Vue源碼作一些基礎的瞭解,若是你已經對基礎的源碼目錄設計等有基礎的瞭解的話,能夠跳過下面這部分。vue

源碼目錄設計

Vue.js 的源碼都在 src 目錄下,其目錄結構以下。java

src
├── compiler        # 編譯相關 
├── core            # 核心代碼 
├── platforms       # 不一樣平臺的支持
├── server          # 服務端渲染
├── sfc             # .vue 文件解析
├── shared          # 共享代碼

複製代碼

compiler

compiler 目錄包含 Vue.js 全部編譯相關的代碼。它包括把模板解析成 AST 語法樹,AST語法樹優化,代碼生成等功能。react

編譯的工做能夠在構建時作(能夠藉助 webpack、vue-loader 等插件);也能夠在運行時作,使用包含構建功能的 Vue.js。編譯是一項耗性能的工做,因此更推薦前者——離線編譯。webpack

core

core 目錄包含了 Vue.js 的核心代碼,包括有內置組件、全局 API 封裝,Vue 實例化、Obsever、Virtual DOM、工具函數 Util 等等。git

platform

Vue.js 是一個跨平臺的 MVVM 框架,它能夠跑在 web 上,也能夠配合 weex 跑在 native 客戶端上。platform 是 Vue.js 的入口,2 個目錄表明 2 個主要入口,分別打包成運行在 web 上和 weex 上的 Vue.js。github

server

Vue.js 2.0 支持了服務端渲染,全部服務端渲染相關的邏輯都在這個目錄下。注意:這部分代碼是跑在服務端的 Node.js,不要和跑在瀏覽器端的 Vue.js 混爲一談。web

服務端渲染主要的工做是把組件渲染爲服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最後將靜態標記"混合"爲客戶端上徹底交互的應用程序。編程

sfc

一般咱們開發 Vue.js 都會藉助 webpack 構建, 而後經過 .vue 單文件來編寫組件。json

這個目錄下的代碼邏輯會把 .vue 文件內容解析成一個 JavaScript 的對象。

shared

Vue.js 會定義一些工具方法,這裏定義的工具方法都是會被瀏覽器端的 Vue.js 和服務端的 Vue.js 所共享的。

接下來咱們來找一下Vue的入口文件,咱們接下來的分析都是基於platform爲web的環境下進行的分析,從 package.json 和 config的 的打包配置中裏能夠看出,運行在web環境 (Runtime only (CommonJS))的入口文件在 web/entry-runtime.js下。

Vue入口文件

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 


複製代碼

initGlobalAPI

在 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 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 鉤子函數
  • init injections and reactivity(這個階段屬性都已注入綁定,並且被 $watch 變成reactivity,可是 $el 仍是沒有生成,也就是DOM沒有生成)
  • 初始化state狀態(初始化了data、props、computed、watcher)
  • 調用created鉤子函數。

在初始化的最後,檢測到若是有 el 屬性,則調用 vm.$mount 方法掛載 vm,掛載的目標就是把模板渲染成最終的 DOM。

Vue代碼初始化的主線邏輯很是分明,使得邏輯和流程很是清楚,這種編程方法值得學習。

最後

如今的部分只是粗略的函數上講了 new Vue 的過程和含義,接下來的文檔會繼續對Vue的源碼進行學習和分析,會接着更細地分析在生命週期lifecyle下每個函數後面具體所作的事情。

相關文章
相關標籤/搜索