Antecedents feed

  • Slash-and-burn era: Dom manipulation by hand, no compatibility concerns; Over time, front-end requirements become more complex, with more complex data and DOM structures to handle.
  • MVVM framework: Solve the problem of view and state synchronization, when the view changes, automatically update data; Automatically updates the view as data changes.
  • Template engine: Good for SEO, high data security, no need to worry about JS being disabled by users, but can’t track DOM state.

Snabbdom

A high performance virtual DOM library

Snabbdom can be seen in vue’s warehouse, and the virtual DOM used by Vue is modified based on Snabbdom.

vnode

A normal JS object is a node description object that describes how to create a real node

export interface VNode {
    / / selector
    sel: string | undefined;  
    data: VNodeData | undefined;
    elm: Node | undefined;
    // Text and children are mutually exclusive
    text: string | undefined;  
    children: Array<VNode | string> | undefined;
    key: Key | undefined;
}
// During patch, check whether the two nodes are the same according to the key and SEL selectors fields of vNode
function sameVnode (vnode1: VNode, vnode2: VNode) :boolean {
  return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel
}
// Determine whether the object is a VNode or a common DOM node by checking whether the object has sel nodes
function isVnode (vnode: any) :vnode is VNode {
  // Identify vNodes by sel attribute
  returnvnode.sel ! = =undefined
}
Copy the code

Virtual dom

  • Problem solved: Describe the relationship between application state and view, rendering state into view. Jquery is an imperative manipulation of DOM, state is not easy to manage, logic chaos; Angular/React/Vue manipulates the DOM declaratively and maintains the state. The framework implements how to manipulate the DOM. The virtual DOM is a way to describe state.

  • Manual DOM manipulation is cumbersome, and it is difficult to track previous DOM states. You essentially recreate the entire DOM each time you change the state of your web page, and your web page will be very slow and you’ll lose focus if you type text. The operation speed of JS is faster than the execution speed of DOM operation. Patch is used to calculate the nodes that really need to be updated, which greatly reduces DOM operation and improves performance.

  • Cross-platform, based on JavaScript objects and independent of the real platform environment.

    Browser render DOM server render SSR native application applet

  • Virtual DOM process: Render function — > vNode — > real node

Snabbdom small example

Create virtual DOM and update nodes through patch
import { init } from "Snabbdom/build/package/init"
import { h } from "Snabbdom/build/package/h"

const patch = init([])

// Argument 1: label + selector
// Parameter 2: the text content of the label
let vnode = h('div#container.cls'.'hello world')
let app = document.querySelector('#app')
// Argument 1: old vNode or DOM element
// Parameter 2: new vnode
// Return a new vnode
let oldnode = patch(app, vnode)
Copy the code

Before the changeThe modified

Function of the Snabbdom module

  • The core library of Snabbdom cannot handle dom element attributes, styles, events, etc. It needs to be implemented through the modules provided by Snabbdom

The official module

  • attributes

    <input type="button" id="p" value="Prop selection" test="Custom Properties" />
    Copy the code

    Custom and predefined attributes of HTML tags. Predefined attributes include Type, ID,value, and name

  • props

    A direct property of the js native object.

  • Dataset, which processes data-xx attributes in HTML

  • class

  • style

  • eventlisteners

Demonstrate the differences between Prop and ATTR using modular features

  • The import module
  • Register modules in the init method
  • The h function uses modules in the second argument
import { init } from "snabbdom/build/package/init"
import { h } from "snabbdom/build/package/h"

import { styleModule } from 'snabbdom/build/package/modules/style'
import { eventListenersModule } from 'snabbdom/build/package/modules/eventlisteners'
import { attributesModule } from "snabbdom/build/package/modules/attributes";
import { propsModule } from "snabbdom/build/package/modules/props";
// register module in init
const patch = init([
  styleModule,
  eventListenersModule,
  attributesModule,
  propsModule
]);

let vnode
function render(attrCheck, propCheck) {
  vnode = patch(vnode, view(attrCheck, propCheck));
}
function view (attrCheck, propCheck, propBox) {
  const attrCheckOps = {
    name: "attr1".type: "checkbox".checked: attrCheck
  };
  if (attrCheck) attrCheckOps.checked = "checked";
  if (propBox) propCheck = propBox;
    The second argument to the h function is the object representing the module configuration, and the string is the text content
    return h("div", [
      h(
        "h1",
        {
          style: {
            backgroundColor: "yellow",}},"Difference between ATTR and Prop."
      ),
      h("input", {
        attrs: attrCheckOps,
      }),
      "Attr control check box",
      h("br"),
      h("input#attrBtn", {
        attrs: {
          type: "button".value: "Attr button selected",},on: {
          click: attrEventHandler,
        },
      }),
      h("hr"),
      h("input", {
        attrs: {
          name: "prop1".type: "checkbox",},on: {
          click: checkboxHandler,
        },
        props: {
          checked:!!!!! propCheck, }, }),"Prop Control check box",
      h("br"),
      h("input#propBtn", {
        props: {
          type: "button".value: "Prop button selected",},on: {
          click: propEventHandler,
        },
      }),
    ]);
}
function attrEventHandler () {
  console.log(Click to trigger attrClick event);
  render(true);
}
function propEventHandler () {
  console.log("Click triggers propClick event");
  render(null.true);
}
function checkboxHandler (e) {
  render(null.null, !e.target.checked);
}
window.addEventListener("DOMContentLoaded".() = > {
  vnode = document.getElementById("app");
  render();
});

Copy the code

Select attR to add “Checked” to the HTML tag

Operation 2: Manually click the check box to deselect the attR mode. You can see that the “Checked” attribute of the ATTR mode still exists, but the check box is not selected. Clicking the check box manually changes the DOM object’s Checked property (prop), not checked (attr) in attributes.

  • When the prop and attr values are Boolean, the browser uses the prop value. If the attr value is changed during initialization, the prop will be updated. If the attR value is changed manually, the prop will not be updated. Modifying prop values does not trigger attR updates
  • Non-boolean values attr and prop are updated simultaneously

Operation 3: Click the Prop check box to uncheck it, and then click the Prop button. The check box cannot be selected



Click the prop button and successfully set checked of props to true



The OBJECT property of the DOM element is still false

Why do we make prop true in our code based on the capabilities provided by the props module and the checked value of the check box is still false?



The props module of Snabbdom source code is used to check whether the PROP value of the DOM is updated by comparing the old and new prop values of the Vnode, so that the PROP value of the DOM element remains unchanged.

So Snabbdom will know that the DOM state has changed as long as we update all the tick box response state changes to the prop object.

Snabbdom also provides hooks for manipulating more complex DOM structures, the most complex of which is the patch method diff process, which compares new and old nodes on the same layer.