Vue responsive principle and virtual DOM implementation

Vue responsive principle and virtual DOM implementation

One of the most important and core concepts in Vue is the reactive system. This system enables Vue to automatically track data changes and automatically update related DOM elements when data changes. This article will discuss the implementation principle and underlying implementation of the Vue responsive system.


1. What is a responsive system

In Vue, we can use the data attribute to define the data of the component. This data can be used in templates, and when this data changes, the related DOM elements are automatically updated. This process is at the heart of a reactive system. For example, we define a count property in a Vue component:

<template>
  <div>{
    
    {
    
     count }}</div>
</template>
<script>
export default {
    
    
  data() {
    
    
    return {
    
    
      count: 0
    }
  }
}
</script>

When we update the value of count in the component, the related DOM element will also be updated automatically:

this.count += 1

How is this process achieved? Next, let's discuss the implementation principle of the Vue responsive system.

2. Implementation principle

The implementation of the Vue responsive system is mainly realized through the Object.defineProperty() method. This method can hijack the properties of the object, so that when the properties of the object change, some operations can be performed automatically.

    In Vue, each component instance has a $dataproperty, which is the component's data object. Vue will convert every property in the object to Object.defineProperty()a method . When we access a property in an object, Vue will record this property . When this property changes, Vue will automatically call all of this property to update the relevant DOM elements. For example, we can manually convert a property in an object to :$datagetter/setter$datagettergetter
$datagetter/setter

let queue = []
function flushQueue() {
    
    
  queue.forEach((watcher) => watcher.run())
  queue = []
}
function queueWatcher(watcher) {
    
    
  queue.push(watcher)
  nextTick(flushQueue)
}
class Watcher {
    
    
  constructor() {
    
    
    queueWatcher(this)
  }
  run() {
    
    
    console.log('更新DOM元素')
  }
}
const data = {
    
     count: 0 }
Object.defineProperty(data, 'count', {
    
    
  get() {
    
    
    console.log('获取count的值')
    return value
  },
  set(newValue) {
    
    
    console.log('设置count的值为', newValue)
    value = newValue
    new Watcher()
  }
})
// 更新count属性
data.count = 1
data.count = 2

When we update the count property, the set() method is triggered and a Watcher object is created. This Watcher object will be added to the queue. When all update operations are completed, Vue will sequentially call the run() method of all Watcher objects in the queue to update the relevant DOM elements.

3. Virtual DOM implementation

    In Vue, in addition to the responsive system, another very important concept is the virtual DOM. Virtual DOM is a lightweight JavaScript object that corresponds to real DOM elements. Vue uses virtual DOM to improve performance and avoid frequent manipulation of real DOM elements.
    Vue's virtual DOM implementation is mainly implemented through the diff algorithm. The diff algorithm compares the differences between two trees and applies those differences to the actual DOM elements.
For example, we can manually implement a simple diff algorithm:

在这里插入代码片function diff(oldNode, newNode) {
    
    
  if (!oldNode) {
    
    
    return {
    
     type: 'add', node: newNode }
  }
  if (!newNode) {
    
    
    return {
    
     type: 'remove', node: oldNode }
  }
  if (oldNode.type !== newNode.type) {
    
    
    return {
    
     type: 'replace', node: newNode }
  }
  if (oldNode.text !== newNode.text) {
    
    
    return {
    
     type: 'text', node: newNode }
  }
  const diffChildren = []
  const oldChildren = oldNode.children || []
  const newChildren = newNode.children || []
  const len = Math.max(oldChildren.length, newChildren.length)
  for (let i = 0; i < len; i++) {
    
    
    const childDiff = diff(oldChildren[i], newChildren[i])
    if (childDiff) {
    
    
      diffChildren.push(childDiff)
    }
  }
  if (diffChildren.length) {
    
    
    return {
    
     type: 'children', children: diffChildren }
  }
}
const oldNode = {
    
    
  type: 'div',
  children: [
    {
    
    
      type: 'p',
      text: '旧的子元素'
    }
  ]
}
const newNode = {
    
    
  type: 'div',
  children: [
    {
    
    
      type: 'p',
      text: '新的子元素'
    }
  ]
}
const diffResult = diff(oldNode, newNode)
console.log(diffResult)

    When we compare two nodes, if the two nodes are the same, then return null. If the two nodes differ, an object describing the differences of the nodes is returned. This object contains a type attribute, used to indicate the type of node difference, and a node attribute, used to indicate the new node.
For example, when we compare the two nodes above, an object is returned describing the difference between the nodes:

{
    
    
  type: 'children',
  children: [
    {
    
    
      type: 'text',
      node: {
    
    
        type: 'p',
        text: '新的子元素'
      }
    }
  ]
}

After we get the description objects of node differences, we can apply these differences to real DOM elements to update the DOM elements.

Four. Summary

Vue is a very powerful and flexible front-end framework, and its responsive system and virtual DOM implementation are one of its core functions. This article discusses the principle of Vue responsive system and virtual DOM implementation and its underlying implementation. I hope this article can help you understand the principles of Vue.

Guess you like

Origin blog.csdn.net/2303_76218115/article/details/129772421