vue源码分析(四)>>:compile

今天分析一下$mount后编译文档节点的执行流程,看下指令和插值都是怎么解析的
 
1. 执行流程
> 在create钩子函数执行完毕后,判断如果传了el,就走进:vm.$mount(vm.$options.el);//5088行 方法;
> 进入$mount方法,需要注意的是vue中定义了两个$mount方法,断点发现是先执行11977这一个然后执行9132这一个;
> 执行第一个$mount时候又走了11757行的compileToFunctions方法,在这个方法里执行了11857行的compile方法;
> 然后执行第二个$mount,然后执行mountComponent,在这里执行beforeMount钩子函数,这里创建watcher,然后执行mounted钩子函数;
 
2. 各流程分析
>2.1 11977行这个$mount方法:没有什么实质性的东西
var mount = Vue.prototype.$mount; // 改变$mount指向
  Vue.prototype.$mount = function (
    el,
    hydrating
  ) {
    debugger
    el = el && query(el);// 获取元素

    // 这里看到el不能是body或者html
    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;// 获取#app里边的内容
        } else {
          {
            warn('invalid template option:' + template, this);
          }
          return this
        }
      } else if (el) {
        template = getOuterHTML(el);
      }
      if (template) {
        /* istanbul ignore if */
        if (config.performance && mark) {
          mark('compile');
        }

        var ref = compileToFunctions(template, { // 11794
          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;

        /* istanbul ignore if */
        if (config.performance && mark) {
          mark('compile end');
          measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
        }
      }
    }
    return mount.call(this, el, hydrating)// 9138
  };
> 2.2 再看11794行的compileToFunctions:这个方法没看明白什么csp什么catch什么根据render转化成方法的,继续接着看11857行的compile:在这里整合了一下配置信息:然后调用baseCompile:
  var createCompiler = createCompilerCreator(function baseCompile (
    template,
    options
  ) {
    // 把html字符串转化成对象形式
    var ast = parse(template.trim(), options);// 9689
    if (options.optimize !== false) {
      optimize(ast, options);
    }
    // 把解析好的html转化成render函数
    var code = generate(ast, options);
    return {
      ast: ast,
      render: code.render,
      staticRenderFns: code.staticRenderFns
    }
  });
在这里将把html字符串转化成render函数然后返回generate里边很复杂以后再详细说;
 
> 2.3再看9138行的$mount:
  Vue.prototype.$mount = function (
    el,
    hydrating
  ) {
    el = el && inBrowser ? query(el) : undefined;
    return mountComponent(this, el, hydrating)
  };
> 2.4 再看4049行的mountComponent方法
function mountComponent (
    vm,
    el,
    hydrating
  ) {
    vm.$el = el;
    callHook(vm, 'beforeMount');

    var updateComponent = function () {
      vm._update(vm._render(), hydrating);
    };

    // we set this to vm._watcher inside the watcher's constructor
    // since the watcher's initial patch may call $forceUpdate (e.g. inside child
    // component's mounted hook), which relies on vm._watcher being already defined
    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
  }

 

over

 

 

 

posted on 2020-09-04 14:56  rainbowLover  阅读(296)  评论(0编辑  收藏  举报