vue源碼學習之初始化過程

初始化過程

初始化過程:init -> $mount -> compile -> new Watcher -> render -> update
在這裏插入圖片描述

  1. src/platforms/web/runtime/index.js:實現$mount
  2. src/core/index:全局api
  3. src/core/instance/index:聲明vue構造函數
  4. src/platforms/web/entry-runtime-with-compiler:覆蓋了$mount
  5. src/core/instance/lifecycle.js mountComponent:執行渲染和更新,虛擬dom -》真實dom

1、定義$mount,patch

src/platforms/web/runtime/index.js
執行掛載方法

Vue.prototype.__patch__ = inBrowser ? patch : noop // 定義一個補丁函數,執行patching算法進行更新

Vue.prototype.$mount = function (  // 定義一個$mount 方法 (掛載根組件到指定宿主元素)
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating) // 執行掛載
}

2、定義全局api

src/core/index.js

initGlobalAPI(Vue)

// src/core/global-api/index.js
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
initUse(Vue) // 實現Vue.use函數
initMixin(Vue) // 實現Vue.mixin函數
initExtend(Vue) // 實現Vue.extend函數
initAssetRegisters(Vue) // 註冊並實現指令,組件,過濾器

3、定義Vue構造函數

src/core/instance/index.js

function Vue (options) { // vue構造函數
  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) // 實現_init函數
stateMixin(Vue) // 狀態相關api,$data,$props,$set,$delete,$watch
eventsMixin(Vue) // 事件相關api,$on,$once,$off,$emit
lifecycleMixin(Vue) // 生命週期,_update,$forceUpdate,$destory
renderMixin(Vue) // 渲染api, _render,$nextTick

src/core/instance/init.js
實現initMixin()方法,創建組件實例,初始化數據、屬性以及事件等等。

export function initMixin (Vue: Class<Component>) { // 創建組件實例,初始化其數據、屬性和事件等等
  Vue.prototype._init = function (options?: Object) { // 在Vue原型中添加_init方法
  ...
  	initLifecycle(vm) // 定義了$parent,$root,$children,$refs,
    initEvents(vm) // 處理父組件傳遞的監聽器($on,$emit)
    initRender(vm) // $slots,$scopedSlots,_c,$createElement
    callHook(vm, 'beforeCreate') // 在beforeCreate生命週期之前執行了以上三個方法
    initInjections(vm) // resolve injections before data/props  獲取注入數據
    initState(vm) // 初始化props,methods,data,computed,watch
    initProvide(vm) // resolve provide after data/props  注入數據
    callHook(vm, 'created')
    ...
  }
 }

4、入口

src/platforms/web/entry-runtime-with-compiler.js
這個文件主要是擴展了$mount的方法,用於處理template和el選項,同時將獲取的模板進行編譯。

const mount = Vue.prototype.$mount // 獲取Vue原型中的 $mount 方法
Vue.prototype.$mount = function ( // 添加一個處理template或者el選項的功能
  el?: string | Element, // el 屬性其實就是掛載點,所有的掛載元素會被Vue生成的DOM替換掉,如果render跟template都不存在,那麼掛載元素的html就會被拿出來當作模板使用。
  hydrating?: boolean
): Component {
  el = el && query(el) // 查找對應的dom,沒有就自己創建一個div
  const options = this.$options // 獲取Vue實例中的參數
  if (!options.render) { // 如果不存在render函數,
  //因此可以看到render的優先級高於template高於el
  	let template = options.template // 纔去找template
  ...
  ...
    // 獲取模板後執行編譯
    //compileToFunctions() 將template字符串轉換成render函數
    const { render, staticRenderFns } = compileToFunctions(template, { // 編譯模板
        outputSourceRange: process.env.NODE_ENV !== 'production',
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this)
      options.render = render // 將render函數保存的options中
      options.staticRenderFns = staticRenderFns
      ...
  }
  return mount.call(this,el,hydrating)
}

無論通過template還是el的方式最終生成的都是render函數。

5、mountComponent

src/core/instance/lifecycle.js

export function mountComponent ( // 執行掛載
	...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章