溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue中Watcher的作用是什么

發布時間:2021-07-09 14:01:45 來源:億速云 閱讀:206 作者:Leah 欄目:web開發

Vue中Watcher的作用是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

就是這個函數:

// Line-7531
  Vue$3.prototype.$mount = function(el, hydrating) {
    el = el && inBrowser ? query(el) : undefined;
    return mountComponent(this, el, hydrating)
  };

第一步query就不用看了,el此時是一個DOM節點,所以直接返回,然后調用了mountComponent函數。

// Line-2375
  function mountComponent(vm, el, hydrating) {
    vm.$el = el;
    /* 檢測vm.$options.render */

    // 調用鉤子函數
    callHook(vm, 'beforeMount');

    var updateComponent;
    /* istanbul ignore if */
    if ("development" !== 'production' && config.performance && mark) {
      /* 標記vue-perf */
    } else {
      updateComponent = function() {
        vm._update(vm._render(), hydrating);
      };
    }

    // 生成中間件watcher
    vm._watcher = new Watcher(vm, updateComponent, noop);
    hydrating = false;

    // 調用最后一個鉤子函數
    if (vm.$vnode == null) {
      vm._isMounted = true;
      callHook(vm, 'mounted');
    }
    return vm
  }

這個函數做了三件事,調用beforeMount鉤子函數,生成Watcher對象,接著調用mounted鉤子函數。

數據雙綁、AST對象處理完后,這里的Watcher對象負責將兩者聯系到一起,上一張網上的圖片:

Vue中Watcher的作用是什么

可以看到,之前以前把所有的組件都過了一遍,目前就剩一個Watcher了。

構造新的Watcher對象傳了3個參數,當前vue實例、updateComponent函數、空函數。

// Line-2697
  var Watcher = function Watcher(vm, expOrFn, cb, options) {
    this.vm = vm;
    // 當前Watcher添加到vue實例上
    vm._watchers.push(this);
    // 參數配置 默認為false
    if (options) {
      this.deep = !!options.deep;
      this.user = !!options.user;
      this.lazy = !!options.lazy;
      this.sync = !!options.sync;
    } else {
      this.deep = this.user = this.lazy = this.sync = false;
    }
    this.cb = cb;
    this.id = ++uid$2;
    this.active = true;
    this.dirty = this.lazy; // for lazy watchers
    this.deps = [];
    this.newDeps = [];
    // 內容不可重復的數組對象
    this.depIds = new _Set();
    this.newDepIds = new _Set();
    // 把函數變成字符串形式`
    this.expression = expOrFn.toString();
    // parse expression for getter
    if (typeof expOrFn === 'function') {
      this.getter = expOrFn;
    } else {
      this.getter = parsePath(expOrFn);
      if (!this.getter) {
        this.getter = function() {};
        "development" !== 'production' && warn(
          "Failed watching path: \"" + expOrFn + "\" " +
          'Watcher only accepts simple dot-delimited paths. ' +
          'For full control, use a function instead.',
          vm
        );
      }
    }
    // 不是懶加載類型調用get
    this.value = this.lazy ?
      undefined :
      this.get();
  };

該構造函數添加了一堆屬性,第二個參數由于是函數,直接作為getter屬性加到watcher上,將字符串后則作為expression屬性。

最后有一個value屬性,由于lazy為false,調用原型函數gei進行賦值:

// Line-2746
  Watcher.prototype.get = function get() {
    pushTarget(this);
    var value;
    var vm = this.vm;
    if (this.user) {
      try {
        value = this.getter.call(vm, vm);
      } catch (e) {
        handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
      }
    } else {
      // 調用之前的updateComponent
      value = this.getter.call(vm, vm);
    }
    // "touch" every property so they are all tracked as
    // dependencies for deep watching
    if (this.deep) {
      traverse(value);
    }
    popTarget();
    this.cleanupDeps();
    return value
  };

  // Line-750
  Dep.target = null;
  var targetStack = [];

  function pushTarget(_target) {
    // 默認為null 
    if (Dep.target) {
      targetStack.push(Dep.target);
    }
    // 依賴目前標記為當前watcher
    Dep.target = _target;
  }

  function popTarget() {
    Dep.target = targetStack.pop();
  }

原型方法get中,先設置了依賴收集數組Dep的target值,user屬性暫時不清楚意思,跳到了else分支,調用了getter函數。而getter就是之前的updateComponent函數:

// Line-2422
  updateComponent = function() {
    vm._update(vm._render(), hydrating);
  };

這個函數不接受參數,所以說傳進來的兩個vm并沒有什么卵用,調用這個函數會接著調用_update函數,這個是掛載到vue原型的方法:

// Line-2422
  Vue.prototype._render = function() {
    var vm = this;
    var ref = vm.$options;
    var render = ref.render;
    var staticRenderFns = ref.staticRenderFns;
    var _parentVnode = ref._parentVnode;
    // 檢測是否已掛載
    if (vm._isMounted) {
      // clone slot nodes on re-renders
      for (var key in vm.$slots) {
        vm.$slots[key] = cloneVNodes(vm.$slots[key]);
      }
    }
    // 都沒有
    vm.$scopedSlots = (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject;
    if (staticRenderFns && !vm._staticTrees) {
      vm._staticTrees = [];
    }
    vm.$vnode = _parentVnode;
    // render self
    var vnode;
    try {
      // 調用之前的render字符串函數
      vnode = render.call(vm._renderProxy, vm.$createElement);
    } catch (e) {
      /* handler error */
    }
    // return empty vnode in case the render function errored out
    if (!(vnode instanceof VNode)) {
      /* 報錯 */
      vnode = createEmptyVNode();
    }
    // set parent
    vnode.parent = _parentVnode;
    return vnode
  };

方法獲取了一些vue實例的參數,比較重點的是render函數,調用了之前字符串后的ast對象:

Vue中Watcher的作用是什么

在這里有點不一樣的地方,接下來的跳轉有點蒙,下節再說。

Vue中Watcher的作用是什么

看完上述內容,你們掌握Vue中Watcher的作用是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女