preface

Learn vue source code, from 0 to 1…

Frameworks such as Vue and React convert their templates to the virtual DOM and then perform subsequent operations. How to convert a DOM to a virtual DOM? Here I use a recursive way to do simple transformation, which is different from the basic implementation of Vue and React, just to better understand DOM and virtual DOM.

Why do we need the virtual DOM in the first place?

In our daily development, DOM often needs to be modified, and frequent operation of real DOM will trigger redrawing and rearrangement, which seriously affects page performance. Therefore, virtual DOM is proposed. As an abstraction of real DOM, DOM information is stored in the form of objects, cached in memory, and real DOM is updated at a time to improve performance.

Prepare knowledge

1. What is DOM?

For detailed DOM native apis, see MDN:DOM

DOM is the interface of JavaScript to operate web pages, fully known as “Document Object Model”. DOM model uses a logical tree to represent a document. The end of each branch of the tree is a node, and each node contains objects.

A node is the smallest unit of a DOM tree. The tree structure of a Document is composed of nodes with different column types (Document, Element, Text).

See MDN:NODE for details about NODE’s native API

Write a simple DOM structure in an HTML fileCopy the code
<div id="root" class="c1">
    <p>hello</p>
</div>
<script>
  const root = document.querySelector('#root')
  console.dir(root)
  console.dir(root.childNodes)
</script>
Copy the code

Print out the DOM structure at the console

2. NODE properties

  1. NodeName: node name, uppercase if element, with # in front of other names.

  2. NodeType: Specifies the node type, usually represented by a number. 1 represents element(which can also be represented by Node.element_node) and 3 represents text(node.text_node).

    If it is Element, nodeName === tagName

    If it is text, then nodeName = #text, tagName = undefined

  3. NodeValue: The value of the current node. For text and comment nodes, nodeValue returns the text content of the node, for attribute nodes, the value of the attribute, and for document and Element nodes, null

The real DOM => virtual DOM

Create a VDom class with attributes: Tag, data, value, Type, children

Starting with the DOM root node, each node is instantiated as a VDom, recursively traversing its children

For text nodes, there are no children, only one text attribute

// Create a VDom class
class VDom {
    constructor(tag, data, value, type) {
      this.tag = tag && tag.toLowerCase() / / the node name
      this.data = data / / property
      this.value = value // Text data
      this.type = type // Node type
      this.children = []
    }
    appendChild(vnode) {
      this.children.push(vnode)
    }
  }

  function getVNode(node) {
    let nodeType = node.nodeType
    let _vnode = null
    if (nodeType === 1) {
      / / element
      let tag = node.nodeName
      let attrs = node.attributes
      let _attrObj = {}
      for (let i = 0; i< attrs.length; i++) {
        _attrObj[attrs[i].nodeName] = attrs[i].nodeValue
      }
      _vnode = new VDom(tag, _attrObj, undefined, nodeType)
      
      let children = node.childNodes
      for (let i = 0; i < children.length; i++) {
        _vnode.appendChild(getVNode(children[i]))
      }
    } else if (nodeType === 3) {
      / / text
      _vnode = new VDom(node.nodeName, undefined, node.nodeValue, nodeType)
    }
    return _vnode
  }
  const vroot = getVNode(document.querySelector('#root'))
  console.log(vroot)
Copy the code

The final converted VDom format is as follows:

Virtual DOM => real DOM

Here’s the thing: What if you create an element node with a nodeName?

How do I create a text node from a piece of text?

CreateElement: Creates an element by specifying its name

CreateTextNode: Creates a text node

The idea is similar to the above, which is to create the DOM recursively and append it to the parent component

function parseVNode(vnode) {
    let type = vnode.type
    let rdom = null
    if (type === 1) {
      rdom = document.createElement(vnode.tag)
      / / element
      let attrs = vnode.data
      for (let key in attrs) {
        rdom.setAttribute(key, attrs[key])
      }
      let children = vnode.children
      for (let i = 0; i < children.length; i++) {
        rdom.appendChild(parseVNode(children[i]))
      }
    } else if (type === 3) {
      / / text
      rdom = document.createTextNode(vnode.value)
    }
    return rdom
}
const realRoot = parseVNode(vroot)
console.log(realRoot)
document.body.appendChild(realRoot)
Copy the code

conclusion

This article is mainly in a recursive way, with native JS to achieve real DOM and virtual DOM direct transformation, is a very basic knowledge point, now many people with the framework for a long time will not use the native method, do these small exercises for the understanding of native JS and reading framework source code are good.

If there is an error in the article please point out in time, don’t blame mo!

Without further ado, go on studying ~~~