• vue $mount挂载实例方法


    源码如下:
    var mount = Vue.prototype.$mount; Vue.prototype.$mount = function ( el, hydrating ) { el = el && query(el); //query是看el是字符串还是组件,如果是字符串就去document.querySelector(el),如果查找到就返回return document.createElement('div'),这也是为什么挂载的dom变成div的原因
    /* istanbul ignore if */
        if (el === document.body || el === document.documentElement) { //不能挂载在body,html
          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) {  //判断是否有render,这也就是我们创建vue项目的时候会让选是Runtime Only 还是 Runtime+Compiler(现在默认选only),看源码推荐Compiler版本,因为抛开 webpack 的 vue-loader
      var template = options.template;
          if (template) {  
            if (typeof template === 'string') {
              if (template.charAt(0) === '#') {
                template = idToTemplate(template);  //这个定义如下const idToTemplate = cached(id => { const el = query(id) return el && el.innerHTML}),看字段是添加缓存还没研究
                /* 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);  //如果不是模板,就获取dom结构,这个返回会是string .例如'<div class='app'><div></div></div>'
          }
          if (template) {
            /* istanbul ignore if */
            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; //这步其实是最重要的拿到render,Compiler版本就是去进行一系列判断然后编译模板template,将它转换成render函数。所以上面的一系列的操作就是为了获取render函数。只是vue提供了很多种方法去编译。
    然后去调用mountComponent方法
        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)  

       };

    
    
      Vue.prototype.$mount = function (
        el,
        hydrating
      ) {
        el = el && inBrowser ? query(el) : undefined;
        return mountComponent(this, el, hydrating) //这里会调用到mountComponent方法
      }; 

    
    
     function mountComponent (  //核心就是把render渲染成vnode,然后实例化一个渲染Watcher,在它的回调函数中会掉用updateComponent方法,最终调用vm._update更新DOM,会完成整个渲染工作 
       el,
      vm, hydrating ) { vm.$el
    = el; if (!vm.$options.render) { vm.$options.render = createEmptyVNode; { /* istanbul ignore if */ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) { warn( //就是用runtime-only版本,已经写render了,还写template会报warn 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ); } else { warn( 'Failed to mount component: template or render function not defined.', vm ); } } } callHook(vm, 'beforeMount'); var updateComponent; /* istanbul ignore if */ if (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); }; } // 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
      Watcher 在这里起到两个作用,一个是初始化的时候会执行回调函数,另一个是当 vm 实例中的监测的数据发生变化的时候执行回调函数,都会调用updateComponent方法
    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
      函数最后判断为根节点的时候设置 vm._isMounted 为 true, 表示这个实例已经挂载了,同时执行 mounted 钩子函数。 这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例
    if (vm.$vnode == null) { vm._isMounted = true; callHook(vm, 'mounted'); } return vm }
  • 相关阅读:
    Algs4-2.3.31运行时间直方图
    Algs4-2.3.30极端情况-各种分布排列时的快排性能
    LintCode Python 简单级题目 111.爬楼梯 (斐波纳契数列 青蛙跳)
    LintCode Python 简单级题目 167.链表求和
    LintCode Python 简单级题目 经典二分查找问题
    LintCode Python 入门级题目 删除链表元素、整数列表排序
    LintCode Python 入门级题目 斐波纳契数列
    LintCode Python 入门级题目 二叉树的最大节点
    Python HTMLTestRunner生成网页自动化测试报告时中文编码报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6
    Python的内置函数open()的注意事项
  • 原文地址:https://www.cnblogs.com/TTblog5/p/12857696.html
Copyright © 2020-2023  润新知