在我心中---Vue 源碼解讀(明天繼續寫吧)

Vue 基礎原理

前言:哥哥教你 斷點學習下

new Vue 做了什麼

各種初始化

初始化流程 描述
initLifecycle 初始化生命週期
initEvents 事件
initRender render 渲染函數
callHook(vm, ‘beforeCreate’);
initInjections resolve injections before data/props
initState 初始化 props,data,method,computed,watch
initProvide resolve provide after data/props
callHook(vm, ‘created’)

在這裏插入圖片描述

  Vue.prototype._init = function (options) {
    var vm = this;
    // a uid
    vm._uid = uid$3++;

    var startTag, endTag;
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      startTag = "vue-perf-start:" + (vm._uid);
      endTag = "vue-perf-end:" + (vm._uid);
      mark(startTag);
    }

    // a flag to avoid this being observed
    vm._isVue = true;
    // merge options
    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
      );
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm);
    } else {
      vm._renderProxy = vm;
    }
    // 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');

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      vm._name = formatComponentName(vm, false);
      mark(endTag);
      measure(("vue " + (vm._name) + " init"), startTag, endTag);
    }

    if (vm.$options.el) {
      vm.$mount(vm.$options.el);
    }
  };

初始化 $mount("#app") 做了什麼

綁定部分生命週期,掛載DIV
在這裏插入圖片描述
第一步:找到掛載div 綁定
第二部:mountComponent 綁定 render 同時 callhook beforeMount,
第三部:Watcher 對象 render 同時監聽渲染 callHook(vm, ‘beforeUpdate’);
第四部:callHook(vm, ‘mounted’);
在這裏插入圖片描述
在這裏插入圖片描述

function mountComponent (  vm,  el, hydrating ) {
  vm.$el = el;
  if (!vm.$options.render) {
    vm.$options.render = createEmptyVNode;
    if (process.env.NODE_ENV !== 'production') {
    ...
  }
  callHook(vm, 'beforeMount');

  var updateComponent;
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    updateComponent = function () {
      var name = vm._name;
      var id = vm._uid;
      var startTag = "vue-perf-start:" + id;
      var endTag = "vue-perf-end:" + id;

      mark(startTag);
      var vnode = vm._render();
      mark(endTag);
      measure(("vue " + name + " render"), startTag, endTag);

      mark(startTag);
      vm._update(vnode, hydrating);
      mark(endTag);
      measure(("vue " + name + " patch"), startTag, endTag);
    };
  } else {
    updateComponent = function () {
      vm._update(vm._render(), hydrating);
    };
  }

  new Watcher(vm, updateComponent, noop, {
    before: function before () {
      if (vm._isMounted && !vm._isDestroyed) {
        callHook(vm, 'beforeUpdate');
      }
    }
  }, true /* isRenderWatcher */);
  hydrating = false;

  // manually mounted instance, call mounted on self
  // mounted is called for render-created child components in its inserted hook
  if (vm.$vnode == null) {
    vm._isMounted = true;
    callHook(vm, 'mounted');
  }
  return vm
}

衍生問題:
document.getElementById 和 document.querySelector 區別

data 值是怎麼綁定的呢

在項目初始化的時候 對data 數據進行 判斷
:注意 不能和methods 種的函數 props 由重複
使用 Object.defineProperty 來進行數據綁定監聽在這裏插入圖片描述在這裏插入圖片描述

data 的值是怎麼 在dom 中進行動態變化的

首先 vue 文件被解析成對象VNode ,在對象裏面獲取 data 中的值
在數據變化後 (set 後)會dep.notify() 通知所有依賴的watch 進行update更新
update 時會重新render
通過 新的 Vnode 進行對比 然後 替換 重新生成 el
由興趣可以跟蹤一下 patch 這個方法 ,很有意思

這裏有個東西 需要注意 虛擬Dom 這些事件是綁定在虛擬dom 上面 簡單來說,綁定事件的時候Dom還沒有注入的 body 裏面

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

事件綁定是怎麼實現的

同上一樣 ,我們的所有綁定之初都是在 VNode 的基礎上 去進行綁定保存的
但是 el 上面的綁定是在 createElement 上面綁定的
具體而言
在chorme 中找到綁定事件 然後向上查找
發現是通過 updateListeners 這方法 再往上走
發現是通過 updateDOMListeners 再網上
發現是通過invokeCreateHooks再網上
發現是通過createElm再網上
發現是通過 patch(不一定是在更新的時候哈,主要是因爲 data 變化的時候會觸發 更新 ,和我測試的環境有關,一般情況到 createElm 就可以了)
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

事件是怎麼綁定在 html 的標籤上面的 (在Vnode 裏面的elm )

差點 看錯了, 在我的理解中虛擬dom 是乾淨的 沒有污染的 隨時可以 注入 html 裏面的
具體 一般是在createdElm 創建的 dom 元素 包括 attr prop addEvent 等。。。然後回掛上 vnode

衍生 問題
爲什麼要用虛擬Dom

  • 虛擬dom 不依賴環境 全是 js 對象,可以做到跨平臺
  • js 執行效率相對 直接操作dom 要更加高效
  • 可以使用diff 方法進行局部最小化更新 不影響其他dom ,即:操作dom 最小化

Vue 中的Watch 對象是原理是

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章