在我心中---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 对象是原理是

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