爲何點擊下面的button
界面會出現自增?segmentfault
<div id="example-2"> <simple-counter></simple-counter> </div> Vue.component('simple-counter', { template: '<button v-on:click="counter += 1">{{ counter }} </button>', data: function () { return { counter: 0 } } }) new Vue({ el: '#example-2'})
數據定義
;數據綁定
;數據響應
;{counter:0}
;observe(data, this)
;observe()
過程當中會將data
這個對象劫持,經過Object.defineProperty
將data
上全部的屬性綁定上getter
和setter
函數;(這是針對對象,對於數組,Vue
經過改寫數組的原生方法來劫持);counter
的值就會觸發getter()
;要是誰改變了counter
的值就會觸發setter()
;好比上述代碼中的button
綁定{{count}}
的時候必定會觸發getter()
;若是是count
的值發生改變就必定會觸發setter()
button
中綁定{{count}}
;button
會產生一個Watcher(vm, exp, cb(newValue,oldValue))
,vm
是Vue
對象,exp
是數據綁定的數據;cb()
的邏輯是用來更新頁面。如今的問題是如何將數據的變化和Watcher
關聯起來。在這裏用到了一個重要的思想就是發佈訂閱模式
;Watcher
初始化的時候會將Dep.target
設置爲this
,也就是Watcher
本身,同時會觸發count
的getter
方法,getter
裏面會調用Dep
的depend
方法,depend
方法會調用Watcher
的addDep
方法,addDep
方法就是將Watcher
本身存放在Dep
的事件池裏面。數組
class Dep { constructor() { this.id = uid++; this.subs = []; } addSub(sub) { this.subs.push(sub) } depend() { if (Dep.target) { Dep.target.addDep(this) } } removeSub(sub) { let ind = this.subs.findIndex(sub); this.subs.splice(ind, 1) } notify() { this.subs.forEach(sub => sub.update()) } } Dep.target = null;
count
的值改變,會觸發setter
裏面的方法,這個方法會調用dep.notify()
;它會告知Dep的事件池裏的存放的Watcher
去執行它的update()
方法;Watcher
的update()
方法;這個方法裏面會獲取count
的新的值,給它的回調cb()
,去更新視圖。Vue
官方給出的示意圖的含義。