Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Vue.js 2.0 deeply responsive principle


May 07, 2021 Vue.js 2.0


Table of contents


Vue.js 2.0 in-depth responsive principle

Most of the basic content we've already talked about, now let's talk about the underlying content. O ne of Vue's most notable features is the response system -- the model is just a normal object, and modifying it updates the view. T his makes state management very simple and intuitive, but it is also important to understand how it works to avoid some common pitfalls. In this section, we'll begin to dig deep into the underlying details of the Vue response system.

How to track changes

Pass a normal Javascript object to a Vue instance as its data option, and Vue traverses its properties and turns them into getter/setters with Object.defineProperty. This is a feature of ES5 and cannot be patched, which is why Vue does not support IE8 and earlier browsers.

Users do not see getter/setters, but internally they let Vue track dependencies and notify them of changes when properties are accessed and modified. The problem here is that the browser console formats getter/setter differently when printing data objects, so you may need to install vue-devtools for a more friendly check interface.

Each component instance has a corresponding watcher program instance that records the property as dependent during component rendering, and then notifies the watcher to recalculate when the setter of the dependency is called, causing the components it is associated with to be updated.

Vue.js 2.0 deeply responsive principle

Change detection issues

Vue cannot detect the addition or deletion of object properties due to the limitations of modern Javascript (and the abandonment of Object.observe). B ecause Vue converts the property to getter/setter when the instance is initialized, the property must be on the data object to allow Vue to convert it so that it is responsive. For example:

var vm = new Vue({
  data:{
  a:1
  }
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的

Vue does not allow the dynamic addition of new root-level responsive properties on instances that have already been created. However, it can use the Vue.set (object, key, value) method to add response properties to nested objects:

Vue.set(vm.someObject, 'b', 2)

You can also use the vm.$set instance method, which is also an alias for the global Vue.set method:

this.$set(this.someObject,'b',2)

Sometimes you want to add properties to an existing object, such as using the Object.assign() or .extend() method. H owever, the new property added to the object does not trigger an update. In this case, you can create a new object that contains the properties of the original object and the new properties:

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

There are also some array-related issues that have been addressed before in List Rendering.

Because Vue does not allow the dynamic addition of root-level responsive properties, you must declare root-level responsive properties, even if it is just an empty value, before initializing an instance:

var vm = new Vue({
  data: {
    // 声明 message 为一个空值字符串
    message: ''
  },
  template: '<div>{{ message }}</div>'
})
// 之后设置 `message` 
vm.message = 'Hello!'

If you do not declare message in the data object, Vue issues a warning that your rendering method is trying to access a property that does not exist.

There is a technical reason behind this limitation, which eliminates a class of boundary conditions in a dependency tracking system and makes Vue instances run more efficiently with the help of a type checking system. This is also important in terms of code maintainability: the data object is like a schema of component state, declaring all the properties above it to make it easier for organizational code to be understood more quickly by other developers or when they re-read it themselves.

The queue is updated asynchronously

You should note that Vue performs DOM updates asynchronously, and whenever data changes are observed, Vue starts a queue that caches all data changes within the same event loop. I f a watcher is triggered more than once, it is pushed into the queue only once. T hen, in the next event loop, Vue refreshes the queue and performs only the necessary DOM updates. Vue internally tries to invoke asynchronous queues using native Promise.then and MutationObserver, and if the execution environment is incompatible, setTimeout (fn, 0) instead.

For example, when you set vm.someData to 'new value', the component is not immediately re-rendered. W hen the queue is refreshed, this component is updated the next time the event loop clears the queue. W e basically don't care about the process, but if you want to do something after the DOM status update, it can be a bit tricky. I n general, Vue encourages developers to follow a data-driven approach and try to avoid direct contact with doMs, but sometimes we do. T o wait for Vue to complete the update DOM after the data change, you can use Vue.nextTick immediately after the data change. T his callback is called after the DOM update is complete. For example:

<div id="example">{{message}}</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: '123'
  }
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
  vm.$el.textContent === 'new message' // true
})

vm.$nextTick() This instance method is particularly convenient to use within the component because it does not require a global Vue, and its callback this is automatically bound to the current Vue instance:

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
    return {
      message: 'not updated'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = 'updated'
      console.log(this.$el.textContent) // => 'not updated'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => 'updated'
      })
    }
  }
})