vue源码解析:vue生命周期方法$mount方法的实现原理

在vue的内部封装了大量的api和方法供开发者调用,$mount方法是其中之一:

用法:

vm.$mount( [elementOrSelector] )

 参数:

  • {Element | string} [elementOrSelector]
  • {boolean} [hydrating]

作用:

  • 如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。
  • 如果没有提供 elementOrSelector 参数,模板将被渲染为文档之外的的元素,并且你必须使用原生 DOM API把它插入文档中。
  • 这个方法返回实例自身,因而可以链式调用其它实例方法。
var mount = Vue.prototype.$mount;
Vue.prototype.$mount = function (el,hydrating) {
  el = el && query(el);
  if (el === document.body || el === document.documentElement) {
    warn(
      "Do not mount Vue to <html> or <body> - mount to normal elements instead."
    );
    return this
  }

  var options = this.$options;
  // resolve template/el and convert to render function
  if (!options.render) {
    var template = options.template;
    if (template) {
      if (typeof template === 'string') {
          if (template.charAt(0) === '#') {
            template = idToTemplate(template);
            /* istanbul ignore if */
            if (!template) {
              warn(
                ("Template element not found or is empty: " + (options.template)),
                this
              );
            }
          }
      } else if (template.nodeType) {
        template = template.innerHTML;
      } else {
        {
          warn('invalid template option:' + template, this);
        }
        return this
      }
    } else if (el) {
      template = getOuterHTML(el);
    }
    if (template) {
      if (config.performance && mark) {
        mark('compile');
      }

      var ref = compileToFunctions(template, {
        outputSourceRange: "development" !== 'production',
        shouldDecodeNewlines: shouldDecodeNewlines,
        shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this);
      var render = ref.render;
      var staticRenderFns = ref.staticRenderFns;
      options.render = render;
      options.staticRenderFns = staticRenderFns;

      if (config.performance && mark) {
        mark('compile end');
        measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
      }
    }
  }
  return mount.call(this, el, hydrating)
};

从源码中可以看到,在vue的实例上挂$mount方法之前,做了一次缓存$mount。这是因为vue的俩个版本造成的,还记得吗,一个是完整版,一个是运行时版本,他们的区别就是有没有模版编译,所以,$mount也就有两个版本,最开始的缓存就是为了,缓存运行时的$mount。下面我们来细看$mount内部是怎么实现的。

从代码中可以看到,该函数可大致分为三部分:

  • 根据传入的el参数获取DOM元素;
  • 在用户没有手写render函数的情况下获取传入的模板template
  • 将获取到的template编译成render函数;

首先,根据传入的el获取dom元素,并判断其不是body或者html,这是因为body或者html替换后会破坏html文档结构。

其次,在用户没有手写render函数的情况下获取传入的模板template。

首先获取用户传入的template选项赋给变量template,如果变量template存在,则接着判断如果template是字符串并且以##开头,则认为templateid选择符,则调用idToTemplate函数获取到选择符对应的DOM元素的innerHTML作为模板。如果template不是字符串,那就判断它是不是一个DOM元素,如果是,则使用该DOM元素的innerHTML作为模板,如果既不是字符串,也不是DOM元素,此时会抛出警告:提示用户template选项无效。如果变量template不存在,表明用户没有传入template选项,则根据传入的el参数调用getOuterHTML函数获取外部模板,不管是从内部的template选项中获取模板,还是从外部获取模板,总之就是要获取到用户传入的模板内容,有了模板内容接下来才能将模板编译成渲染函数。获取到模板之后,接下来要做的事就是将其编译成渲染函数,把模板编译成渲染函数是在compileToFunctions函数中进行的,该函数接收待编译的模板字符串和编译选项作为参数,返回一个对象,对象里面的render属性即是编译好的渲染函数,最后将渲染函数设置到$options上。

这就是$mount函数的实现过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值