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

来源:https://www.cnblogs.com/erbingbing/archive/2018/04/08/8746756.html
-Advertisement-
Play Games

vueJs 源碼解析 (三) 具體代碼 在之前的文章中提到了 vuejs 源碼中的 架構部分,以及 談論到了 vue 源碼三要素 vm、compiler、watcher 這三要素,那麼今天我們就從這三要素逐步瞭解清楚 好了,話不多說, let's do it 在這之前,我們需要 對上文中講到的 vu ...


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)

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

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 資料庫的三大特性可謂是:實體屬性和關係。 實體:表; 屬性:表中的數據(欄位); 關係:表與表之間的關係。 資料庫設計三大範式(重點): 第一範式(1NF):數據表中的每一列(每個欄位)必須是不可拆分的最小單元,也就是確保每一列的原子性; 第二範式(2NF):滿足1NF後,要求表中的所有列,都必須依 ...
  • 一、用Log列印日誌 二、Toast用法 三、在活動中使用Menu 首先在res目錄下新建menu文件夾,接著在這個文件夾下新建一個名叫main的菜單文件,在main.xml中添加如下代碼 回到Activity中重寫onCreateOptionsMenu()方法,編寫如下代碼(返回true表示允許創 ...
  • 一、view鉤子 view鉤子有2個,ngAfterViewInit和ngAfterViewChecked鉤子。 1、實現ngAfterViewInit和ngAfterViewChecked鉤子時註意事項 以父組件調用子組件方法 中例子為基礎,在父組件中實現ngAfterViewInit和ngAft ...
  • 一、什麼是slot 在使用組件時,我們常常要像這樣組合它們: 當需要讓組件組合使用,混合父組件的內容與子組件的模板時,就會用到slot , 這個過程叫作內容分發( transclusion )。 註意兩點: 1.< app>組件不知道它的掛載點會有什麼內容。掛載點的內容是由<app >的父組件決定的 ...
  • 原型與原型鏈是學習JavaScript這門語言不能不理解的兩個重要概念,為什麼?因為JavaScript是一門基於原型的語言。 怎麼理解“JavaScript是一門基於原型的語言”?在軟體設計模式中,有一種模式叫做原型模式,JavaScript正是利用這種模式而被創建出來。先來瞭解下原型模式的概念... ...
  • 自己跟著網上教程複習上學期的HTML+CSS,因為已經忘得差不多了,而且現在學的js也要以HTML+CSS為基礎,堅持每天持續更新。 n B/S 網路結構 Browser/Server 瀏覽器/伺服器,這是現在最流行的網路模式。如新浪網、鳳凰網等。 C/S Client/Server 客戶端/伺服器 ...
  • 昨天編輯朋友圈文章,無法修改提交的bug終於找到了,原因是用錯了一個標點... 把req點body寫成req逗號body,印象深刻,發人深省。 編輯後,終於可以修改成功了。 雖然只是一個小小的bug,,但是印象實在太過深刻。 所以說寫代碼的時候不用心,改bug的時候就耽誤一天。 晚上還嘗試做了一個刪 ...
  • 組件之間通信可以用下圖表示: 組件關係可分為父子組件通信、兄弟組件通信、跨級組件通信。 一、自定義事件 當子組件需要向父組件傳遞數據時,就要用到自定義事件。 子組件用$emit ()來觸發事件,父組件用$on()來監昕子組件的事件。 父組件可以直接在子組件的自定義標簽上使用v-on 來監昕子組件觸發 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...