Depth Vue.js responsive principle
First, create an application Vue
new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h => h(App), }).$mount('#app');
Second, the application instantiates a Vue in the end what happened?
- this._init()
- callHook(vm, 'beforeCreate')
- observe(vm._data)
vm._data = vm.$options.data()
proxy(vm,
_data, key) 代理到vm上访问
function proxy(vm, _data, key)() { Object.defineProperty(target, key, { get() { return vm._data.key }, set(val) { vm._data.key = val } }) }
- callHook(vm, 'created')
- mountComponent (vm. $ mount execution mountComponent after execution)
- callHook(vm, 'beforeMount')
- new Watcher(vm, updateComponent)
updateComponent = const () => { // Create Virtual dom const the vnode = vm._render () // create a virtual dom process equivalent to the following lines of code // const the vnode = VM. $ options.render.call (VM, VM . $ createElement) // update EL $ vm._update (the vnode) }
- callHook(vm, 'mount')
In the above behaviors occur among both Step 3 and Step 7 complement each other; we also need to care about the most, to clarify both, vue responsive mastered the basic principles
Third, how to track data changes
We all know that the data is changed views also will be updated, so first of all we have to know how to monitor data changes
class Observer { constructor(value) { this.value = value this.walk(value) } walk(obj) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) } } } function defineReactive(obj, key) { Object.defineProperty(obj, key, { get() { // 数据被访问 return obj.key }, set(val) { if (val === obj.key) { return } //Updated data obj.key = Val } }) }
Fourth, the definition of a class publication subscriptions Dep
When we are in the process of creating a virtual dom, that is executed vm $ createElement method, may be used to the same data fields (eg: vm.name) in multiple places., That more subscribers subscribe to the update name, therefore defines a publish-subscribe in the Dep class in Vue
class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } depend() { if (Dep.target) { this.addSub(Dep.target) } } notify() { this.subs.forEach(sub => sub.update()) } removeSub(sub) { const i = this.subs.findIndex(sub) if (i > -1) { this.subs.splice(i, 1) } } }
Fifth, data subscribers
Subscribe to updated data who in the end, we take a look at the following scenario
<! - Scene 1 -> < div > Name: {{userInfo.name}}, full name: fullName {{}} </ div >
export default { data() { return { userInfo: { name: 'junhua', }, } }, mounted() { // 场景2 this.$watch('name', (newVal, val) => { // ... }) }, // 场景2 watch: { name(newVal, val) { // ... } }, computed() { // 场景3 fullName() { return `yang${this.userInfo.name}` } } }
From above of the sample code, updating the subscription data of the scene are:
- Template interpolation:
new Watcher(vm, updateComponent)
data changes, update components - vm $ watch:. listening to an individual data to do some logical operations
- computed usage scenarios: Calculated Properties
Thus the subscriber data comprise a parameter expOrFn ( [Function|String]
), the callback data updates need to be performed after, as follows:
class Watcher { constructor(vm, expOrFn, cb) { this.vm = vm if (typeof expOrFn === 'function') { this.getter = expOrFn } else { this.getter = parsePath(expOrFn) } this.cb = cb || () => {} this.value = this.get() } get() { Dep.target = this const value = this.getter.call(this.vm, this.vm) Dep.target = undefined return value } update() { const val = this.value const newVal = this.get() this.cb.call(this.vm, newVal, val) } }
Sixth, the ultimate observer Observer
class Observer { constructor(value) { this.value = value this.walk(value) } walk(obj) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i],) } } } function defineReactive(obj, key) { const dep = new Dep() Object.defineProperty(obj, key, { get() { // 依赖收集,收集订阅者Watcher实例 dep.depend() // 数据被访问 return obj.key }, SET (Val) { IF (Val === obj.key) { return } // data updated obj.key = Val // notify subscribers Watcher instance update dep.notify () } }) }
Seven summary
We look back at the instance of the application Vue most important points
observe(vm._data) // vm.$mount() const componentUpdateWatcher = new Watcher(vm, updateComponent)
updateComponent when updating render component, or accesses a plurality of data templates interpolation, when accessing the data, added to the componentUpdateWatcher getter interceptor as by a plurality of subscriber-dependent, whenever one of the data update, the execution setter function, the corresponding dependence will notify subscribers componentUpdateWatcher execution update, namely the implementation of updateComponent; Vue data responsive to this purpose has been reached, this picture again Tell me what network on a good understanding
github address Source: blog Garden - Yang Junhua , please indicate the source: Yang Junhua