diffHTML

v1.0.0

The easy-to-use Virtual DOM, built for the web!

Transitions

A unique concept to diffHTML, these transitions are activated as first class events whenever elements are added, removed, changed, and when attributes and text have changed.

By returning promises you can halt rendering until they have completed. This could allow you to easily build keyframe based animations or integrate tools like anime.js that support Promises.


Available states

There are many states you can listen to, they get added globally and allow you to do filtering. You add them using the addTransitionState method.

import { addTransitionState } from 'diffhtml';

Attached

For when an element is attached to the DOM.

addTransitionState('attached', (element) => {
  console.log(element);
});

Detached

For when an element leaves the DOM.

addTransitionState('detached', (element) => {
  console.log(element);
});

Replaced

Whenever two elements are replaced at render time this is called with the old and new elements.

addTransitionState('replaced', (oldElement, newElement) => {
  console.log(oldElement, newElement);
});

Attribute changed

For when attributes have changed.

addTransitionState('attributeChanged', (element, attrName, oldValue, newValue) => {
  console.log(element, attrName, oldValue, newValue);
});

Text changed

For when text has changed in either TextNodes or SVG text elements.

addTransitionState('attributeChanged', (element, oldValue, newValue) => {
  console.log(element, oldValue, newValue);
});


Add transition

Adds a global transition listener. With many elements this could be an expensive operation, so try to limit the amount of listeners added if you're concerned about performance.

Since the callback triggers with various elements, most of which you probably don't care about, you'll want to filter. A good way of filtering is to use the DOM matches method. It's fairly well supported (http://caniuse.com/#feat=matchesselector) and may suit many projects. If you need backwards compatibility, consider using jQuery's is.

You can do fun, highly specific, filters:

addTransitionState('attached', function(element) {
  // Fade in the main container after it's attached into the DOM.
  if (element.matches('body main.container')) {
    $(element).stop(true, true).fadeIn();
  }
});

If you like these transitions and want to declaratively assign them in tagged templates, check out the diffhtml-inline-transitions plugin.

A note about detached/replaced element accuracy

When rendering Nodes that contain lists of identical elements, you may not receive the elements you expect in the detached and replaced transition state hooks. This is a known limitation of string diffing and allows for better performance. By default if no key is specified, the last element will be removed and the subsequent elements from the one that was removed will be mutated via replace.

What you should do here is add a key attribute with a unique value that persists between renders.

For example, when the following markup...

<ul>
  <li>Test</li>
  <li>This</li>
  <li>Out</li>
</ul>

...is changed into...

<ul>
  <li>Test</li>
  <li>Out</li>
</ul>

The transformative operations are:

  1. Remove the last element
  2. Replace the text of the second element to 'out'

What we intended, however, was to simply remove the second item. And to achieve that, decorate your markup like so...

<ul>
  <li key="1">Test</li>
  <li key="2">This</li>
  <li key="3">Out</li>
</ul>

...and update with matching attributes...

<ul>
  <li key="1">Test</li>
  <li key="3">Out</li>
</ul>

Now the transformative operations are:

  1. Remove the second element


Remove transition

Removes a global transition listener. When invoked with no arguments, this method will remove all transition callbacks. When invoked with the name argument it will remove all transition state callbacks matching the name, and so on for the callback.

// Removes all registered transition states.
diff.removeTransitionState();

// Removes states by name.
diff.removeTransitionState('attached');

// Removes states by name and callback reference.
diff.removeTransitionState('attached', callbackReference);

Edit on GitHub