#Trackira
Virtual DOM libraries can be designed in many ways depending on the problems it is trying to solve, and it can be a challenging task to pick the right library to use.
Trackira try to solve this with being a boilerplate you can build upon. It's goal is not to be the fastest or the best, but possessing the best code structure and also be compatible with the DOM standards today.
Trackira output an Observable of "Virtual DOM Elements", to keep performance fast by patching the actual DOM with only the minimum necessary changes.
You can find a benchmark here
Supported features
- Custom elements,
- SVG and MathML support
- xlink and xml namespace support
- Type extensions
- Server side rendering
- mounting / unmounting
- updates
- patching
- DOM level O events
- lifeCycle hooks
Example
// creating the virtual treevar tree = ; // setting start countvar count = 0; // creating a virtual node { return Trackira;} var vnode = ; // mount the virtual nodevar mountId = tree; // render a new node and update the tree each second;
The above example can be compared with the example of virtual-dom.
Virtual nodes
Trackira.Element()
Trackira.Element()
create a real DOM node, and accepts an optional data object and an optional string or array of children.
E.g. new new Trackira.Element("div", {}, [new Text("Heeey!")])
. Other virtual nodes are available as well - both text and comment node.
The optional data object contains this configurable values:
key: String|Integer props {} attrs: {} events: {} data: hooks: {}
Example:
var h = Trackirah var vnode = ;
Attributes
Element attributes can be set with the attrs{}
property. The attribute name are always the same as in HTML. If you provide a boolean for the attribute value. The attribute will be added with an empty string if it's a true value, and removed otherwise.
var h = Trackirah; // img element with src and alt attributes; // input element with an id and class
Non-ASCII symbols are supported and can be used example in class names.
Inline style (css)
For inline style, you have to set the unit ( e.g. 'px') yourself. Values that need an unit, but don't have one, will not be set.
var h = Trackirah; // Element with style object;// Element with style string;
Keys
Keys are unique and are attached to a virtual node, to ensure that only the elements which were really changed are updated. Even if elements were added/removed before or moved to another position. While common operations like appending and prepending nodes are optimized, it is also very fast at updating random changes like sorting or filtering.
// ensuring right focusvar mountId h = Trackirah tree = ; var from = ; var to = ;var active = false { // negative value active = !active; return active ? from : to; } // mount mountId = tree; ;
Children
var h = Trackirah; // span element with one child // span element with children
Virtual DOM node methods
Each virtual DOM node has it's own methods:
- .render() - render the virtual node, and return a single DOM element
- .toHTML() - create HTML markup server-side
- .patch() - patch a virtual node with a real DOM node
- .detach() - Remove a real DOM element from where it was inserted
- .equalTo() - Checks if two virtual nodes are equal to each other, and they can be updated
Examples
node // render the virtual node node // patch the virtual node with a real DOM node node // remove the node node // returns boolean - true / false
Virtual tree
The API provides all necessary functions to create, update and remove virtual DOM nodes to/from the real DOM.
And many of the API features are the same as for other Virtual DOM libraries.
.mount()
Mounting to the document.body
.
var tree = foo = "h1" {} "Foo visited Bar";tree;
Mounting to element with an id - #mount-point
.
tree;
Mounting to element with a class - .mount-point
.
tree;
Mounting to element with DOM element - document.getElementById("test")
.
tree;
You have probably realized that it supports CSS Selectors.
You can also mount with a factory
- function.
var h = Trackirah tree = render = { var children = "Hello, " "World!!"; return ;}// Mount the tree tree;
With Trackira you also got more advanced options such as mounting with a unique ID identifer.
var bookedId = tree;var mountId = tree
.unmount()
When you unmount a virtual tree, you can choose to unmount them all, or only one tree. Note that the unmount()
function needs to be called with the mount identifier.
tree; // unmount a virtual tree with the mount identifier tree; // unmount all virtual trees
.update()
Once a virtual tree is mounted, you can update it. This API method takes one or two arguments. If no virtual node are set - as the second argument - it will only update already mounted node. E.g. changing / updating it's focus, or diff / patch the child nodes.
tree; // update focus on already mounted node
With two arguments, you can update the existing node with another virtual node as shown in this example:
// create and mount a virtual nodevar tree = ;var h = Trackirah;var foo = var mountId = tree; // new element to updatevar newFoo = ; // update the tree with the mount identifiertree;
If want to update all mounted virtual trees, you can do it like this:
tree.update();
.mountPoint()
This method needs one argument - the unique number created when you mount a virtual tree
// returns a real DOM node where the virtual tree are mounted
.children()
This method needs one argument - the unique number created when you mount a virtual tree
// return a overview over all children to the mounted tree
.mounted()
.mounted()
returns true if the virtual DOM node are mounted into the DOM, false otherwise. You can use this method to guard asynchronous calls.
// return a boolean - true / false - if current tree are mounted // returns a list over all mounted virtual trees
Detach
Trackira.detach()
let you remove virtual nodes.
Example on detaching / removing an element node:
var container = document;var node = "div";var element = node;container;// container.childNodes.length equal to 1 node;// container.childNodes.length equal to 0
Patching operations
There are one main API methods for patching / diffing.
Trackira.patch()
For patching children of a real DOM node, you use Trackira.patch()
.
This method takes a DOM root node, and a set of DOM patches. The patching will only happen if the children are different.
Example patching a text node:
var h = Trackirah;var from = ;var to = ;// patch the nodefrom;
Another example:
// patching a HTML propertyvar h = Trackirah;var from = ;var to = ;// patch the nodefrom;
Patch children on a real DOM node
var h = Trackirah oldChildren = ; newChildren = ; // 'Trackira.patch' are only used for patching / diffing the childrenTrackira;
Server rendring
Trackira supports server rendring. Use .toHTML()
to turn virtual DOM nodes into HTML server-side. Properties get converted into attribute values.
// toHTML boolean propertiesvar element = Trackira; html = element; // result: <input autofocus>
// convert properties to attributesvar element = Trackira; html = element; // result: <form class="login" accept-charset="ISO-8859-1" accesskey="h"></form>
// .toHTML SVG attributesvar svg = Trackira; html = svg; // result: <circle cx="60" cy="60" r="50"></circle>
// .toHTML a commentvar comment = Trackira; html = comment; // result: <!-- Foo like Bar -->
var node = Trackira; html = node; // result: <div><span>hello, terrible world!!</span></div>"
// preserve UTF-8 entities and escape special html characters var node = Trackira; html = node; // result: <span>测试&"'<></span
Event system
Trackira's is a cross-browser wrapper around the browser's native event, and each event are managed in a delegated way. The event handlers will be passed instances of
SyntheticEvent
, a cross-browser wrapper around the browser's native event. It has the same interface as the browser's native event, including
stopPropagation()
and preventDefault()
, except the events work identically across all browsers.
To activate
the event management, you wouldt need to initialize it with Trackira.initEvent() first
. Like this:
Trackira; 'div' events: { ; } ;
After you have initialized the events, a set of common events are automatically bound to document body, and ready to be used.
Note!! You can use the events with or without the on
prefix. E.g. onclick` or click
.
Common event types
Trackira normalizes events so that they have consistent properties across different browsers and attach them to the current document.
You controll this events with the bind()
and unbind()
API methods.
Supported common events:
- blur
- change
- click
- contextmenu
- copy
- cut
- dblclick
- drag
- dragend
- dragenter
- dragexit
- dragleave
- dragover
- dragstart
- drop
- focus,
- input
- keydown
- keyup
- keypress
- mousedown
- mousemove
- mouseout
- mouseover
- mouseup
- paste
- scroll
- submit
- touchcancel
- touchend
- touchmove
- touchstart
- wheel
.bind() and .unbind()
This methods let you control the use of the common events. Here is an example:
// create virtual treevar tree = ; // initialize the eventsvar Evt = Trackira; // stop listen to the 'click' eventEvt; // try 'unbind()' to unbind event // the event will not work because you unbinded itvar vnode = "button" events: { ; } "Click me!"; // mount elementtree;
Show a set of events you are listening to.
// initialize the eventsvar Evt = Trackira; console;
Lifecycle Methods
Various methods are executed at specific points in a virtual node's lifecycle. This hooks are executed at different steps. Following hooks are provided:
updated
- called every time an update occur on a virtual nodecreated
- called once a virtual node has been createddetach
- called when a virtual node is going to be removeddestroy
- called on element removal
Animated transitions can be supported through "created" & "destroy" hooks.
// using 'created' hook on create var params tag = "div" hooks: { params = Arrayprototypeslice; } ; var element = tag; // params are now equal to [tag, element]
Example on detach / destroy hooks when you are detaching a node
var destroyHook; var h = Trackirah; var params = ; var tag =
Shadow DOM
Trackira supports Shadow DOM, and should work right out of the box with it. Shadow root is found and automatically dealt with.
Sources:
Many of the ideas for this virtual DOM are comming from the open source community. Many clever brains, with many clever ideas. Trackira is mainly inspired by
- ReactiveJS ( text, comment and element prototype)
- JSBlocks - ( virtual text and virtual comment nodes)
- Virtual DOM ( the virtual DOM structure itself)
- Kivi - Patching / diffing algorithm
- citoJS - performance tips
- REACT - mounting / unmounting and HTML markup server-side
- vdom-to-html - for server side rendring
- dom-layer - ideas about structure
Installing
Download the repo and run:
npm install
Commands:
Trackira uses gulp and Babel, and the commands are pretty straight forward:
// runs the unit tests$ npm gulp // build the library$ npm gulp build // bundle the library for our unit tests$ npm gulp browserify // show a istanbul coverage statistic on cmd line$ npm gulp coverage // runs unit tests$ npm gulp test // run the headless unit tests as you make changes$ npm gulp watch // set up a livereload environment for our spec runner$ npm gulp test-browser
Community
- Ask "how do I...?" questions on Slack:
- Propose and discuss significant changes as a GitHub issues
Testing
All unit tests in the Travis CI are server-side. However. If you run this:
HTML file in your browser after you have cloned the repo, will you see unit tests running client-side.
Contribution
Want to contribute? Just send a pull request. All major development are in the dev branch. Master contains more or less a stable release.