Implement a simple virtual dom in an object-oriented design

what is virtual dom

Everyone should know that the real dom is the document object of html. Each element in the document corresponds to a real dom object. By operating the real dom object, we can obtain, modify, add and delete HTML elements.

So the question is, what is virtual dom? In my opinion, virtual dom is an object that stores page element information. Like real dom, it stores information such as the content of elements, the attributes of elements, and the structure between elements. But the difference is that the properties of the virtual dom are more streamlined, and the virtual dom cannot be rendered directly, it needs to be converted into a real dom to render.

As shown in the figure below, I printed the real dom of a div element on the console, and you can see that this object has many attributes. Manipulating such a large object is expensive. Especially when the data changes frequently, the dom must be modified every time the data changes, which is likely to cause performance problems. But if the virtual dom is introduced, when the data changes, we first modify the virtual dom. Since the virtual dom object is small in size and the operation speed is fast, there will be no major performance problems if it is modified multiple times in a short period of time. Finally, the results of multiple modifications are synchronized to the real dom at one time, so that the real dom only needs to be operated once, and the performance is greatly optimized.
insert image description here

Realization of virtual dom

Below I will implement the creation and rendering of a simple virtual dom object.

The Vdom class in the following code is the virtual dom class I defined. There are three attributes tagName, attrs, and children in the class, and their meanings are tag name, tag attribute, and child elements.

Vdom has a member method render(), the responsibility of this method is to render the Vdom object, and its return value is a real dom object. Its general process is as follows:

  • If tagName is 'text', it means this is a text node, then call document.createTextNode() to create a text node object and return
  • If tagName is not 'text', it means that this is an html element, then call document.createElement() to create a dom object, and traverse attrs to set the attribute value of the dom object. Then traverse the children array, create a Vdom object for the child element and render it, and add the real dom object of the child element. Finally, just return.
class Vdom{
    
    
  constructor(tagName, attrs, children){
    
    
    this.tagName = tagName
    this.attrs = attrs || {
    
    }
    this.children  = children || []
  }
  render(){
    
    
    let htmlElement 
    if(this.tagName == 'text'){
    
    
      htmlElement = document.createTextNode(this.attrs['nodeValue'])
    }
    else {
    
    
      htmlElement = document.createElement(this.tagName)
      // 设置真实dom的属性
      for(let key in this.attrs){
    
    
        // 很怪,直接htmlElement.style = this.attrs['style']不起作用
        if(key === 'style'){
    
    
          for(let styleKey in this.attrs['style']){
    
    
            htmlElement.style[styleKey] = this.attrs['style'][styleKey]
          }
        }
        else {
    
    
          htmlElement[key] = this.attrs[key]
        }
      }
      // 为子元素创建真实dom,并添加到当前dom下
      for(let child of this.children){
    
    
        let childVdom = new Vdom(child.tagName, child.attrs, child.children)
        htmlElement.append(childVdom.render())
      }
    }
    return htmlElement
  }
}

Finally, write code to test it out.

The following is my test code. You can see that I call the Vdom class to create a series of virtual dom objects. There are multi-level nesting and reuse relationships between them. Finally, I convert the virtual dom into a real dom and add it to the body element. Next, the effect of running in the browser is shown in the figure:

insert image description here

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="./vdom.js"></script>
  <script>
    let textVdom = new Vdom('text', {
      
      nodeValue: '你好,再见'})
    let h1Vdom = new Vdom('h1', {
      
      style: {
      
      color: 'red'}}, [textVdom])
    let liVdom = new Vdom('li', {
      
      style: {
      
      color: 'white'}}, [textVdom])
    let pVdom = new Vdom(
      'p', 
      {
      
      style: {
      
      width: '200px', height: '200px', 'background-color': 'purple'}}, 
      [h1Vdom, liVdom]
    )
    let divVdom = new Vdom(
      'div', 
      {
      
      style: {
      
      width: '320px', height: '320px', 'background-color': 'grey'}}, 
      [h1Vdom, liVdom, pVdom]
    )
    console.dir(divVdom)

    // 渲染,把虚拟dom转换成真实dom
    let htmlDivElement = divVdom.render()
    document.querySelector('body').append(htmlDivElement)
  </script>
</body>
</html>

Guess you like

Origin blog.csdn.net/m0_52744273/article/details/129652091