This is the 8th day of my participation in the August More Text Challenge
The preface
Vue’s three core, responsive, VDOM, template compilation, we have studied responsive before, the next is to read VDOM, so I decided to start from VDOM inspiration library, Snabbdom, today we will look at what snabbDOM gave us inspired.
Install snabbdom
- Clone on Github: Here is the TS version.
$ git clone https://github.com/snabbdom/snabbdom
Copy the code
- Use NPM: here is the build JS version.
npm i -D snabbdom
Copy the code
Snabbdom profile
Snabbdom is a virtual DOM.
- Do you know what a Virtual DOM is? In layman’s terms, a Virtual DOM is a JS object that is an abstraction of the real DOM, retaining only useful information and describing the structure of the DOM tree more lightly.
- Snabbdom is an implementation that describes the real DOM as a javascript object of a particular format, and then converts that javascript object of a particular format into the real DOM.
- JS objects of that particular format are called vnodes.
The Node with the VNode
The actual Node object.
<a href="http://www.baidu.com">Copy the code
Virtual Node (VNode) corresponding to a real Node.
{" sel ":" a ", "data" : {props: {href: 'http://www.baidu.com'}}, "text", "baidu", the children: "undefined", elm: "undefined", key:"undefined" }Copy the code
We found that the properties on the real Node are described in the virtual Node, and the information is not lost, just a different representation. A VNode can be transformed into a real Node through the patch function, which can be combined into a DOM and mounted to the page
Vnode definition
export interface VNode { sel: string | undefined; / / tag name data: VNodeData | undefined; / / label attribute data in children: Array < VNode | string > | undefined; / / child tags elm: Node | undefined; / / the current node corresponding real DOM node text: string | undefined; / / the current node text key: key | undefined; } export interface VNodeData {props? : Props; attrs? : Attrs; class? : Classes; style? : VNodeStyle; dataset? : Dataset; on? : On; hero? : Hero; attachData? : AttachData; hook? : Hooks; key? : Key; ns? : string; // for SVGs fn? : () => VNode; // for thunks args? : Array<any>; // for thunks [key: string]: any; // for any other 3rd party module }Copy the code
Let’s take a look at a simple example where we will show how to convert a Vnode object into a real Node and display it on a page
The import {h} from 'snabbdom/SRC/package/h' import {init} from 'snabbdom/SRC/package/init' / / / / create the patch function parameters: Const patch = init([]) const patch = init([]) Let vnode = h('div#container. CLS ', 'Hello World') const app = document.getelementById ('app') // let the virtual node on the DOM tree // first argument: Return value: vnode const oldVNode = patch(app, vnode)Copy the code
We can see that displaying a piece of content on a page requires three steps
- Create a virtual node (VNode) using the h function.
- Defines the seat to mount the node.
- Using the patch function, make the VNode a real Node and mount it to the Node seat passed in.
Summary: From the above case, we can not help wondering, how does h function create Vnode? How does the patch method convert a Vnode into a real Node and mount it to the page?
Decrypt h function
When you look at a function, you first look at the input and the output parameters. The h function takes three arguments,
- An SEL string representing the name of the tag,
- The second argument is the definition of the module data (i.e., class, click, etc.)
- The third parameter is the form of the child node
export function h(sel: string): VNode export function h(sel: string, data: VNodeData | null): VNode export function h(sel: string, children: VNodeChildren): VNode export function h(sel: string, data: VNodeData | null, children: VNodeChildren): VNode export function h (sel: any, b? : any, c? : any): VNodeCopy the code
We also found that function H handles different arguments passed in through function overloading.
if (c ! == undefined) { if (b ! == null) { data = b } if (is.array(c)) { children = c } else if (is.primitive(c)) { text = c } else if (c && c.sel) { children = [c] } } else if (b ! == undefined && b ! == null) { if (is.array(b)) { children = b } else if (is.primitive(b)) { text = b } else if (b && b.sel) { children = [b] } else { data = b } } if (children ! == undefined) { for (i = 0; i < children.length; ++i) { if (is.primitive(children[i])) children[i] = vnode(undefined, undefined, undefined, children[i], undefined) } }Copy the code
After processing, you can isolate the parameters required by the VNode function.
export function vnode (sel: string | undefined,
data: any | undefined,
children: Array<VNode | string> | undefined,
text: string | undefined,
elm: Element | Text | undefined): VNode {
const key = data === undefined ? undefined : data.key
return { sel, data, children, text, elm, key }
}
Copy the code
We can see that the vNode method takes four arguments and returns a vNode object. Summary: the h function overloads the accepted parameters, separates the data, and then gives it to the VNode function, which finally converts it into a VNode object of the corresponding format. Let’s look at a real case
let vnode = h( "div#container.cls", { class: { active: true, }, style: { background: "#fff", }, on: { click: clickFn, }, dataset: { name: "coolFish", }, hook: { init: function () { console.log("init"); }, create: function () { console.log("create"); }, insert: function () { console.log("insert"); }, prepatch: function () { console.log("beforePatch"); }, update: function () { console.log("update"); }, postpatch: function () { console.log("postPatch"); }, destroy: function () { console.log("destroy"); }, remove: function (ch, rm) { console.log("remove"); rm(); },},}, [h("p", {}, "I am the first Vnode")]); function clickFn() { console.log("click"); }Copy the code
The above h function generates the following VNode. We can see that its parent container is a div with the id container. It has class, click events, style, why convert to the virtual DOM, because fine comparison is using the new virtual DOM to compare with the old virtual DOM, figuring out how to update as little as possible, and then reflect it to the real DOM. With a VNode, you can mount the VNode to the page using the patch function.