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對象負責將兩者聯系到一起,上一張網上的圖片:

可以看到,之前以前把所有的組件都過了一遍,目前就剩一個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的作用是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。