接:javascript
手摸手從0實現簡版Vue --- (依賴收集)github
手摸手從0實現簡版Vue --- (批量更新&nextTick)數組
使用watch有兩種方法,第一種直接調用vm.$watch,第二種是在選項中配置watch屬性。異步
watch: {
msg: {
handler: function (newValue, oldValue) {
console.log('watch:', {
newValue,
oldValue
})
},
immediate: true
}
}
// or
vm.$watch('msg', function(newVal, oldVal) {
console.log({ newVal, oldVal })
})
複製代碼
咱們要去實現一個vm.$watch
方法,$watch
方法的話作了兩件事:函數
userDef
中分離 handler
和 其餘的 opts
{ user: true }
標記爲用戶watcher。下面看代碼:post
Vue.prototype.$watch = function(expr, userDef) {
const vm = this;
let handler = userDef;
const opts = { user: true }
if (userDef.handler) {
handler = userDef.handler;
Object.assign(opts, userDef);
}
new Watcher(vm, expr, handler, opts);
}
複製代碼
首先把傳入的字符串作爲函數返回,例如'msg'
轉化爲 util.getValue(vm, 'msg')
。ui
這一步很是關鍵,由於new Watcher
的時候默認調用一次get
方法,而後執行getter
函數,這個過程會觸發msg
的getter
,讓msg
的dep
添加一個用戶watcher
,完成依賴收集。
constructor(vm, exprOrFn, cb = () => {}, opts = {}) {
this.vm = vm;
this.exprOrFn = exprOrFn;
if (typeof exprOrFn === 'function') {
this.getter = exprOrFn;
} else if (typeof exprOrFn === 'string') {
+ // 用戶watcher
+ // 解析expr,取到data上的值
+ // 取值的時候完成依賴收集
+ this.getter = function () {
+ return util.getValue(vm, exprOrFn);
+ }
+ }
+ this.immediate = opts.immediate
+ // 用戶添加的watcher,標記一下
+ this.user = opts.user
this.cb = cb;
this.opts = opts;
this.id = id++;
this.deps = [];
this.depsId = new Set();
// 咱們但願在回調函數中返回一個新值,一箇舊值,因此咱們須要記錄getter返回的值
+ this.value = this.get();
+ if (this.immediate) {
+ this.cb(this.value)
+ }
}
複製代碼
完成依賴收集後,當咱們的數據發生變化後,調用Watcher
的run
方法,進行值的比對,若是發生變化,就去執行這個watcher
的callback
。
class Watcher {
run() {
const newValue = this.get();
if (newValue !== this.value) {
this.cb(newValue, this.value);
this.value = newValue;
}
}
}
複製代碼
這樣的話,咱們的 $watch
也就實現了,下面咱們去實現initWatch
方法,遍歷下用戶傳入的watch
配置,進行watcher
添加:
function initWatch(vm) {
const watch = vm.$options.watch;
for (const key in watch) {
const userDef = watch[key];
createWatcher(vm, key, userDef);
}
}
複製代碼
此時咱們使用最開始的兩種方法去監聽咱們的msg
值的變化,而後異步去更新一下咱們的msg
值,兩個log都會正常執行了。
這樣的話咱們的watch
也就簡單實現啦~
代碼點擊=> 傳送門