Depth Vue Responsive principle

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?

  1. this._init()
  2. callHook(vm, 'beforeCreate')
  3. 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
    }
  })
}
  1. callHook(vm, 'created')
  2. mountComponent (vm. $ mount execution mountComponent after execution)
  3. callHook(vm, 'beforeMount')
  4. 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) 
}
  1. 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:

  1. Template interpolation: new Watcher(vm, updateComponent)data changes, update components
  2. vm $ watch:. listening to an individual data to do some logical operations
  3. 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

 

Guess you like

Origin www.cnblogs.com/yangjunhua/p/11374430.html