virtualdom

tools to work with a virtual dom

Stars
31

virtualdom

tools to work with a virtual dom

Inspiration

React is probably the first to have done this and gain massive hype with it. However it grew extremely large, being >500k unminified.

mithril.js also has a virtual dom and claims to do dom diffing. However, it is a complete MVC framework, complete with its own promises implementation, xhr, etc. But at least it is very small, although not very readable.

virtual-dom/ mercury seems like a very good solution. It has a lot more flexibility and deals with properties instead of with attributes by default.

And of course, I don’t want to merely use a library. I want to know and understand the technology, so I might as well implement it myself :-)

Installation

$ component install Swatinem/virtualdom

Usage

fromDOM(node)

Creates a virtual dom node for the real DOM node.

toDOM(vnode)

Creates a real DOM node for the virtual dom vnode.

diff(from, to)

Creates a list of patches to transform from to to.

applyPatch(node, patches)

Applies a list of patches, see below for patch details.

Internal data structures

Virtual DOM Node

A text node is simply a js string.

A comment node is {comment: 'comment content'}

And a normal node is represented as:

{
	key: 'optional internal identifier used for sorting',
	tag: 'div',
	ns: 'optional namespace, like "http://www.w3.org/2000/svg" for svg'
	class: ['array', 'of', 'classes'],
	style: {position: 'absolute', borderRadius: '5px'},
	data: {dataset: 'key value pairs'},
	attributes: {'id': 'id', 'value': 'key value pairs for attributes'},
	children: [array, of, children, or, a, single, child]
}

class, data and style are handled separately from other attributes since they have array or hashtable-like accessors in the real DOM.

Patch

{
	node: [], // chain of `childNodes` positions, starting at the room node
	// and patches, which are all optional:
	addClasses: [],
	removeClasses: [],
	setStyles: {},
	removeStyles: [],
	setAttributes: {},
	removeAttributes: [],
	setData: {},
	removeData: [],
	setContent: '', // for text and comment nodes
	childPatches: [/* see below */]
}
// and childPatches:
{
	type: 'insert',
	child: newChild,
	index: 0, // required, will insert at the specified index
}
{
	type: 'replace',
	child: newChild,
	index: 0, // required, index of the old child
}
{
	type: 'remove'
	index: 0
}
// might be good to have, but very difficult to implement as a diff
{
	type: 'move'
	from: 0, // old index
	to: 1 // new index
}

TODO

  • reorder / move child nodes
  • support innerHTML for unsafe code

License

LGPLv3

Released as free software as part of ChatGrape