Vue源码—挂载阶段


在这里插入图片描述

初始化阶段

Vue 的初始化过程(new Vue(options))都做了什么?

  • 处理组件配置项

    • 初始化根组件时进行了选项合并操作,将全局配置合并到根组件的局部配置上
    • 初始化每个子组件时做了一些性能优化,将组件配置对象上的一些深层次属性放到 vm.$options 选项中,以提高代码的执行效率
  • 初始化组件实例的关系属性,比如 $parent、$children、$root、$refs

  • 处理自定义事件

  • 调用 beforeCreate 钩子函数

  • 初始化组件的 inject 配置项,得到 ret[key] = val 形式的配置对象,然后对该配置对象进行响应式处理,并代理每个 key 到 vm 实例上

  • 数据响应式,处理 props、methods、data、computed、watch 等选项

  • 解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上

  • 调用 created 钩子函数

  • 如果发现配置项上有 el 选项,则自动调用 $mount 方法,也就是说有了 el 选项,就不需要再手动调用 $mount 方法,反之,没提供 el 选项则必须调用 $mount

  • 接下来则进入挂载阶段

export function initMixin (Vue) {
  Vue.prototype._init = function (options) {
    const vm = this
    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')

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

vm.$mount

使用 vm.$mount( [elementOrSelector] ),返回vm实例本身,

var MyComponent = Vue.extend({
 template:'<div>Hello!</div>',
})
<!-- 创建并挂载到#app(会替换#app) -->
new MyComponent().$mount('#app');

new MyComponent().$mount({el:'#app'});

var component = new MyComponent().$mount();
document.getElementById('app').appendChild(component.$el);

完整的构建版本中,vm.mount 首先会检查template或el选项所提供的模板是否已经转换成渲染函数(render函数)。
如果没有,则立即进入编译过程,将模板编译成渲染函数,完成之后再进入挂载与渲染的流程中。
完整版包含只包含运行时版本。

const mount = Vue.prototype.$mount;
Vue.prototype.$mount = function(el){
 <!-- 做些什么 -->
 return mount.call(this,el);
}

通过函数劫持,可以在原始功能上新增一些其他功能,在完整版中有编译功能

编译器

  • 1 是否有render选项
    在实例化Vue.js时给出了render选项,那么template其实是无效的,
    因为不会进入模板编译的流程,而是直接使用render选项中提供的渲染函数。

  • 2 是否设置了template选项
    如果用户没有通过template选项设置模板,那么会从el选项中获取HTML字符串当作模板。
    如果用户提供了template选项,那么需要对它进一步解析,因为这个选项支持很多种使用方式。
    template选项可以直接设置成字符串模板,也可以设置为以#开头的选择符,还可以设置成DOM元素。

  • 3 从不同的格式中将模板解析出来

  • 4 渲染函数
    获取模板之后,下一步是将模板编译成渲染函数,通过执行compileToFunctions函数可以将模板编译成渲染函数并设置到this.options上

只包含运行时版本的vm.$mount的实现原理

1、$mount方法将ID转换为DOM元素后,使用mountComponent函数将Vue.js实例挂载到DOM元素上。

2、将实例挂载到DOM元素上指的是将模板渲染到指定的DOM元素中,而且是持续性的,以后当数据(状态)发生变化时,依然可以渲染到指定的DOM元素中。

3、实现这个功能需要开启watcher。

4、mountComponent方法会判断实例上是否存在渲染函数。如果不存在,则设置一个默认的渲染函数createEmptyVNode,该渲染函数执行后,会返回一个注释类型的VNode节点。

5、事实上,如果在mountComponent方法中发现实例上没有渲染函数,则会将el参数指定页面中的元素节点替换成一个注释节点,并且在开发环境下在浏览器的控制台中给出警告。

  • mountComponent具体实现
export function mountComponent(vm,el){
 if(!vm.$options.render){
  vm.$options.render = createEmptyVNode;
  if(process.env.NODE_ENV !== 'production'){
   <!-- 在开发环境发出警告 -->
  }
  
  <!-- 触发生命周期钩子 -->
  callHook(vm,'beforeMount');
  
  <!-- 挂载 -->
  vm._watcher = new Watcher(vm,()=>{
   vm._update(vm._render())
  },noop);
  
  <!-- 触发生命周期钩子 -->
  callHook(vm,'mounted');
  return vm;
 }
}
  1. vm._update作用:调用虚拟DOM中的patch方法来执行节点的比对与渲染操作。

  2. vm._render作用:执行渲染函数,得到一份新的VNode节点树。

  3. vm._update(vm._render())作用:先调用渲染函数得到一份最新的VNode节点树,然后通过vm._update方法对最新的VNode和上一次渲染用到的旧VNode进行对比并更新DOM节点。简单来说,就是执行了渲染操作。

在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值