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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM