Vue源碼學習(二)$mount() 後的作的事(1)

  Vue實例初始化完成後,啓動加載($mount)模塊數據。vue

(一)Vue$3.protype.$mount node

      

        標紅的函數 compileToFunctions 過於複雜,主要是生AST 樹,返回的 ref 以下:react

      

 

          render 是瀏覽器虛擬機編譯出來的一個函數。咱們點進入能夠看到以下代碼(本身調整後空格換行後的數據)    express

(function(){
   with(this){
    return _c('div',{
    attrs:{"id":"app"}},
    [_c('input',{directives:[{name:"model",rawName:"v-model",value:(message),expression:"message"}],
    attrs:{"type":"text"},domProps:{"value":(message)},
    on:{"input":function($event){
      if($event.target.composing)return;message=$event.target.value}}}),
      _v(_s(message)+"\n")])
   }
})

  跳過這個複雜的函數。瀏覽器

  這裏做者涉及的很奇妙,由於 mount.call(this, el, hydrating)  中的 mount 定義以下 app

  var mount = Vue$3.prototype.$mount;dom

 Vue$3.prototype.$mount = function (el, hydrating) {
        el = el && inBrowser ? query(el) : undefined;
        return mountComponent(this, el, hydrating) //vm._watcher 賦值
    };

  後來又重寫了$mount 方法:ide

  Vue$3.prototype.$mount = function (el, hydrating) {   }函數

(二)mountComponent () 函數oop

         組件安裝

 1 function mountComponent(vm, el, hydrating) {
 2         vm.$el = el; 
 3         if (!vm.$options.render) {
 4             //若是不存咋,則建立一個空的虛擬節點
 5             vm.$options.render = createEmptyVNode;
 6         }
 7         callHook(vm, 'beforeMount');
 8 
 9         var updateComponent;
10         if ("development" !== 'production' && config.performance && mark) {
11             //此處另外一種 updateComponent = 。。。。
12         } else {
13             updateComponent = function () {
14                 vm._update(vm._render(), hydrating); //渲染DOM
15             };
16         }
17         //noop 空函數,
18         vm._watcher = new Watcher(vm, updateComponent, noop); //生成中間件 _watcher
19         hydrating = false;
20 
21         // $vnode不存在,,則手動安裝實例,自啓動
22         // mounted is called for render-created child components in its inserted hook
23         if (vm.$vnode == null) {
24             vm._isMounted = true;
25             callHook(vm, 'mounted');
26         }
27         return vm //調用 實例加載鉤子函數,返回vue實例
28     }

  Watcher是一個十分複雜的對象,是溝通 Observer與 Compile 的橋樑做用。

 (3)Watcher對象

     一、構造函數

   Watcher的構造函數並不複雜,主要是爲當前Watcher 初始化各類屬性,好比depIds,newDeps,getter 等,

  最後調用 Watcher.prototype.get(),讓Dep收集此Wather實例。

   

  Watcher構造函數會將 傳入的第二個參數轉換 this.getter 屬性;

  因爲 this.lazy=false,會當即進入 Watcher.prototype.get()。

    二、Watcher.prototype.get()

  繞了一大圈,這個函數其實也就調用了 傳入構造函數的第二個參數。

 1 Watcher.prototype.get = function get() {
 2         pushTarget(this);
 3         var value;
 4         var vm = this.vm;
 5         try {
 6             //初始化時 最終 調用咱們傳入的 updateComponent
 7             // vm._update(vm._render(), hydrating)
 8             value = this.getter.call(vm, vm);
 9         } catch (e) {
10         } finally {
11             if (this.deep) {
12                 traverse(value);
13             }
14             popTarget();
15             this.cleanupDeps();
16         }
17         return value
18     };

  此時 this.getter = vm._update(vm._render(), hydrating);  開始渲染渲染DOM,這裏十分重要。

  先 執行 Vue.prototype._render(),代碼以下

 

 這裏 render 即是生成的AST代碼。

 接下來會按照 以下順序 觸發各類函數:

 代理函數 proxyGetter() ==>  reactiveGetter() => 執行 render裏面的函數 _c ;

 執行完後,將建立的vnode直接返回。

 讓咱們再仔細看看 defineReactive$$1() 函數,爲元素自定義get/set方法。

 1  function defineReactive$$1(obj, key, val, customSetter, shallow) {
 2         var dep = new Dep();//依賴管理
 3         /* 此時obj 是帶有__ob__屬性的對象,key是msg  */
 4         var property = Object.getOwnPropertyDescriptor(obj, key);//返回鍵描述信息
 5         if (property && property.configurable === false) {
 6             //不能夠修改直接返回
 7             return
 8         }
 9 
10         var getter = property && property.get;
11         var setter = property && property.set;
12 
13         var childOb = !shallow && observe(val);
14         Object.defineProperty(obj, key, {
15             enumerable: true,
16             configurable: true,
17             get: function reactiveGetter() {
18                 var value = getter ? getter.call(obj) : val;
19                 if (Dep.target) {
20                     dep.depend();
21                     if (childOb) {
22                         childOb.dep.depend();
23                         if (Array.isArray(value)) {
24                             dependArray(value);
25                         }
26                     }
27                 }
28                 return value
29             },
30             set: function reactiveSetter(newVal) {
31                 var value = getter ? getter.call(obj) : val; //獲取當前值,是前一個值
32                 if (newVal === value || (newVal !== newVal && value !== value)) {
33                     //值沒有發生變化,再也不作任何處理
34                     return
35                 }
36                 /* eslint-enable no-self-compare */
37                 if ("development" !== 'production' && customSetter) {
38                     customSetter();
39                 }
40                 if (setter) {
41                     setter.call(obj, newVal);//調用默認setter方法或將新值賦給當前值
42                 } else {
43                     val = newVal;
44                 }
45                 childOb = !shallow && observe(newVal);
46                 dep.notify();//賦值後通知依賴變化
47             }
48         });
49     }
defineReactive$$1

 說的不太清楚,下篇文章繼續說。

相關文章
相關標籤/搜索