marko-vdom

This module provides an optimized virtual DOM implementation where each virtual DOM node is API compatible with real DOM nodes for the minimal subset that is required to support DOM diffing/patching using morphdom.

Overview

Each virtual DOM node supports the following properties and methods required by morphdom:

Unlike with real DOM nodes, node.attributes can either be an Array of Attr objects or an Object (where each property represents an attribute. e.g., { "class": "foo", "id": "bar" })

In addition to the standard DOM node methods and properties, a virtual DOM node must also provide a node.actualize(document) method. The node.actualize(document) will be called when the virtual DOM node needs to be upgraded to a real DOM node so that it can be moved into the real DOM.

A virtual DOM node may choose to implement isSameNode(anotherNode) to short-circuit diffing/patching a particular DOM subtree by treating two nodes as the "same"

A virtual DOM node may choose to implement the non-standard assignAttributes(targetNode) to optimize copying the attributes from the virtual DOM node to the target DOM node

marko-vdom is namespace aware and will work correctly with SVG and MathML elements.

While marko-vdom exposes an API that can be used directly, the terse API is designed to be used with a compiler that generates JavaScript code.

Usage

Create an element with a fixed number of attributes and a fixed number of children

The above code will generate a virtual DOM tree that, when converted to a real DOM, will be the following:

<div>

<ahref="http://ebay.com"data-marko-same-id="abc123">

eBay

</a>

</div>

For the static link, both the virtual DOM node and the real DOM node will be marked with an "id" that identifies the two nodes as the "same" node in order to short-circuit DOM/diffing patching. That is:

var realStaticLink =staticLink.actualize(document);

console.log(staticLink.isSameNode(realStaticLink));//Output: true

Document fragments

Document fragments are containers for child nodes that can be appended as children nodes, but the actual DocumentFragment node is never directly visited when walking the DOM using node.firstChild and node.nextSibling. Instead, the children (if any) of a DocumentFragment node are treated as direct children of the parent of the DocumentFragment node. A DocumentFragment node can be modified with new children even after it has been inserted into the DOM.

var createElement =require('marko-vdom').createElement;

var div =createElement('div');

documentFragment.appendChild(createElement('div'));

var documentFragment =div.appendDocumentFragment();

documentFragment.appendChild(createElement('span',{ class:'foo'}));

documentFragment.appendChild(createElement('span',{ class:'bar'}));

/*

Output DOM:

<div>

<span class="foo"></span>

<span class="bar"></span>

</div>

*/

Benchmarks

This library includes some benchmarks to compare performance with the real DOM (and React). To run the benchmarks:

npm run benchmark

This will open a web page in your browser that you can use to run a variety of benchmarks.

We are interested in the following performance characteristics:

Creation time - the time it takes to construct a [virtual] DOM tree

Walk time - the time it takes to walk a [virtual] DOM tree using firstChild and nextSibilng

We encourage you to run the benchmarks on your machine and in various browsers. If you see any problems with the benchmarks, or if you would like clarifying information please open a Github issue.

Shorthand method for creating an HTMLElement node and appending it as a child.

hasAttributeNS(namespaceURI, name) : boolean

isSameNode(otherNode) : boolean

Called by morphdom to determine if the target HTMLElement (either virtual or real) node is the same as the current node. The key passed in to the constructor is used to do determine if the other node is the "same" node. If the other node is a real DOM node then the key is pulled from the data-markokey attribute.

Shorthand method for appending a node as a child. The provided is automatically cloned (using a shallow clone) since it is assumed that this method will be called to append a static/memoized DOM node and the original DOM node should not be modified.