vueJs 源碼解析 (三) 具體代碼


vueJs 源碼解析 (三) 具體代碼

在之前的文章中提到了 vuejs 源碼中的 架構部分,以及 談論到了 vue 源碼三要素 vm、compiler、watcher 這三要素,那么今天我們就從這三要素逐步了解清楚

好了,話不多說, let's do it

在這之前,我們需要 對上文中講到的 vuejs 的源碼是 flow 寫法的問題進行一個簡化。 畢竟還有有工具是可以解決的。

可以用babel-plugin-transform-flow-strip-types去轉化下即可。
	
1、 npm install --save-dev babel-plugin-transform-flow-strip-types

2、 .babelrc 文件中

{
  "plugins": ["transform-flow-strip-types"]
}
	 

具體轉換方法見 github地址

一、 instance 實例化入口 核心代碼
/src/core/instance/index.js

import { initMixin } from './init'				// 實例化 混合 
import { stateMixin } from './state'			// 各類數據應用 混合
import { renderMixin } from './render'			// render 函數等 混合
import { eventsMixin } from './events'			// 例如 父子組件的 emit on 事件
import { lifecycleMixin } from './lifecycle'	// 這個暫時比較模糊,后面的文章更新
import { warn } from '../util/index'			// warn 報錯工具 在控制台經常會看到的 vue 的warn

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&  
    !(this instanceof Vue)             // 這里就是判斷當前 this 的 prototype 是否是 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

一、 instance 實例化入口 核心代碼 之 init.js

核心代碼區塊一:


if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options);
} else {
      vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), 
      options || {}, vm);
}

解析:

判斷傳入的值當中是否有組件,如果有則先實例化組件。

核心代碼區塊二:


    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');

解析:

看字面上的意思是分別一次 實例化了 生命周期、事件、渲染函數 、回調鈎子 ‘beforeCreate’、

依賴注入、狀態、 提供 、回調鈎子 ‘created’、

對,看到這里我們還是很奇怪這些東西是干嘛的?

那么下面我們繼續依次往下看:

一、實例化生命周期 initLifecycle


  vm.$parent = parent;
  vm.$root = parent ? parent.$root : vm;

  vm.$children = [];
  vm.$refs = {};

  vm._watcher = null;
  vm._inactive = null;
  vm._directInactive = false;
  vm._isMounted = false;
  vm._isDestroyed = false;
  vm._isBeingDestroyed = false;

看上去是增加了一系列的 屬性。但是還是不知道這個有什么用。不着急,我們繼續往下看。

二、實例化生命周期 initEvents


export function initEvents(vm) {
  vm._events = Object.create(null);
  vm._hasHookEvent = false;
  // init parent attached events
  const listeners = vm.$options._parentListeners;
  if (listeners) {
    updateComponentListeners(vm, listeners);
  }
}

再走到這步的時候就會發現, vm.$options 這個對象 頻頻出現在我們的視野中,如果每次都不能理解的話。就會遇到 理解障礙。 那么 我們就需要 做一個 最簡單的測試用例。 (實際的把 vue 跑起來)

三、new Vue({ options }) Vue 最簡單的測試用例

我們在created 鈎子下打印 this 對象 部分結果如下

console.log(this)
// console.log(this)
_events: {}
_hasHookEvent :false
_inactive :null
_isBeingDestroyed :false
_isDestroyed :false
_isMounted: true
_isVue: true

這里我們就能夠看到比較清晰的一些屬性了 在 init.js 中的第一步 initLifecycle.js 中定義的

// console.log(this)
_events: {}					// 事件對象集合
_hasHookEvent :false		// 是否有鈎子事件
_inactive :null				// 未知
_isBeingDestroyed :false	// 是否要銷毀
_isDestroyed :false			// 是否已經銷毀
_isMounted: true			// 是否已掛載
_isVue: true				// 是否是 Vue 對象

這里我們就再回到 initLifecycle.js 源碼 中去看

  const options = vm.$options;
  let parent = options.parent;
  if (parent && !options.abstract) {
    while (parent.$options.abstract && parent.$parent) {
      parent = parent.$parent;
    }
    parent.$children.push(vm);
  }

  vm.$parent = parent;
  vm.$root = parent ? parent.$root : vm;

  vm.$children = [];    //  這里定義的 children  數字對象未知是什么意思
  vm.$refs = {};        //  這里定義的 refs 對象依然未知

走到這一步 大概對 vm.$options 這個對象 有個初步的了解,但是還有部分依然是未知。好了,我們繼續往下走。

四、 我回到 第二步 實例化生命周期 initEvents


export function initEvents(vm) {
  vm._events = Object.create(null);
  vm._hasHookEvent = false;
  // init parent attached events
  const listeners = vm.$options._parentListeners;
  if (listeners) {
    updateComponentListeners(vm, listeners);
  }
}

給 vm 對象 新增了一個 _events 對象 , 並且會去判斷 vm.$options 是否有父級的事件監聽。


propsData : undefined
_componentTag : "App"
_parentElm : null
_parentListeners : undefined
_parentVnode : VNode {tag: "vue-component-1-Apps-test", data: {…}, children: undefined, text: undefined, elm: div.test11, …}
_refElm : null
_renderChildren : undefined

_parentListeners 值為空。 這里我們做一個大膽的假設: 是否有組件的引用的時候這個值就會發生改變。 那么下面我們簡單的測試下。新增一個基礎組件.

// 驗證失敗:這個值依然還是為 空

// 但是弄清楚了一個問題:

this.$root   				// 為根對象
this.$root.$parent  		// 根對象的 父屬性一定是為空
this.$root.$children		// 根對象的 子代屬性一定是 一個數組。

// 如果你引用的 組件 
this.$root.$children[0]		// 為第一個組件
this.$root.$children[1]		// 為第二個組件
...

// 以此類推

好,我們接着往下看

五、 initRender(vm)

第五步: 比較核心的 渲染功能。

今天先到這里... 先下個班,回家繼續整理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM