Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/skatejs/dom-diff

Library for efficiently diffing and patching virtual and real DOM fragments.
https://github.com/skatejs/dom-diff

Last synced: about 2 months ago
JSON representation

Library for efficiently diffing and patching virtual and real DOM fragments.

Awesome Lists containing this project

README

        

# Dom Diff

Skate's DOM Diff is a virtual DOM library for diffing, patching and converting between virtual and real DOM trees.

[![Sauce Test Status](https://saucelabs.com/browser-matrix/skatejs-dom-diff.svg)](https://saucelabs.com/u/skatejs-dom-diff)

- Serialise to and from read DOM trees
- Diff virtual trees and patch real trees
- Web worker support

```sh
npm install skatejs-dom-diff
```

## Usage

Where `options` are accepted, you may provide:

- `done` If specified, diffing is performed in a web worker and this callback is called when it's done.

### `diff(source, target, options)`

Diffs two virtual trees.

```js
/** @jsx h **/
import { diff, h } from 'skatejs-dom-diff';

const source =

source
;
const target =
target
;
const instructions = diff(source, target);
```

The `patchInstructions` is an `array` that can be passed to `patch()` to update the `source` tree. Before passing the instructions to `patch()`, however, your source tree must be associated to real DOM nodes. This can be done by using `mount()` or by converting them to a tree using `toDom()`.

### `fragment([virtualNodeOrNodes])`

Creates a virtual fragment. You can pass nothing to create an empty fragment:

```js
import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment();
```

A single virtual node:

```js
import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment(

);
```

An array of virtual nodes:

```js
import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment([

, ]);
```

Or even a virtual fragment:

```js
import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment(fragment(

));
```

### `h(name, props, ...childrenOrText)`

Creates a virtual node.

```js
//

text or...

h('div', { className: 'my-class' }, 'text or...', h('span'));
```

Or you could just use JSX:

```js
/** @jsx h **/
//

text or...

text or...

```

#### Attributes

By default, `h` only sets properties, but you can specify attributes you want to set by passing the special `attributes` prop:

```js
//



```

#### Aria attributes

You can pass `aria-*` attributes using `attributes` but you can also specify the `aria` prop:

```js
//



```

#### Data attributes

Like the `aria` prop, you can also use the `data` prop:

```js
//



```

#### Events

Events are bound using the special `events` prop:

```js
const click = e => doSomethingWith(e);


```

### `merge()`

The `merge()` function is convenience for calling `diff()` and `patch()` sequentially. As with `diff()`, you must ensure the `source` virtual tree has been associated to real nodes first.

```js
/** @jsx h **/
import { diff, h } from 'skatejs-dom-diff';

const source =

source
;
const target =
target
;
const dom = mount(source);
merge(source, target);
```

### `mount(vdom[, root])`

Mounts the `vdom` to the real `root` DOM node. It returns the `root` node. If the `root` node was not specified, it automatically creates a `

` and returns it.

```js
/** @jsx h **/
import { h, mount } from 'skatejs-dom-diff';

const div = mount(

some text

);
```

Is the same thing as:

```js
/** @jsx h **/
import { h, mount } from 'skatejs-dom-diff';

const div = document.createElement('div');
mount(

some text

, div);
```

It's more than likely that you'll just mount it directly to the document:

```js
/** @jsx h **/
import { h, mount } from 'skatejs-dom-diff';

mount(

some text

, document.getElementById('app'));
```

### `patch()`

Takes instructiosn created using `diff()` and performs them on the associated DOM nodes that each instructions is for.

```js
/** @jsx h **/
import { diff, h, mount, patch } from 'skatejs-dom-diff';

const source =

source tree

;
const target =

target tree

;
const instructions = diff(source, target);

mount(source, document.getElementById('app'));
patch(instructions);
```

### `render()`

A highly convenient function for continually rendering a given template.

```js
/** @jsx h **/
import { h, render } from 'skatejs-dom-diff';

const root = document.getElementById('app');
const renderer = render((root) => (

{root.someProp}


));

// Set the prop to render with
root.someProp = 'test 1';

// Initial render:

test 1


renderer(root);

// Update the prop
root.someProp = 'test 2';

// Re-render:

test 2


renderer(root);
```

### `text()`

Returns a virtual text node:

```js
import { text } from 'skatejs-dom-diff';

const vText = text('my text node');
```

### `toDom()`

Convers a virtual tree to a *real* DOM tree, event listeners and all:

```js
import { toDom } from 'skatejs-dom-diff';

const vdom =

I will soon be real!


const dom = toDom(vdom);

//

I will soon be real!


console.log(dom.outerHTML);
```

### `toVdom()`

Converts a real DOM tree into a virtual tree. It only copies over attributes. Event listeners can't be copied because the standard DOM APIs don't provide a way to get bound listeners.

*Properties currently aren't copied either, but is being worked on.*

```js
import { toVdom } from 'skatejs-dom-diff';

const dom = document.createElement('p');
dom.textContent = 'I will soon be fake!';

const vdom = toVdom(dom);
```

### `types`

The types of patches that can occur. Currently these are:

```js
import { types } from 'skatejs-dom-diff';

const {
APPEND_CHILD,
REMOVE_CHILD,
REMOVE_ATTRIBUTE,
REPLACE_CHILD,
SET_ATTRIBUTE,
SET_EVENT,
SET_PROPERTY,
TEXT_CONTENT
} = types;
```

### Web workers

You can tell the differ to do its work in a web worker simply by passing a `done` callback option to any of the three major entry functions (`diff()`, `merge()`, `render()`).

#### `diff(source, target, options)`

In the case of `diff()`, it's called once the diffing algorithm has finished in the worker and passed the `instructions`. The patch `instructions` are the only argument passed into the callback.

```js
/** @jsx h */
import { h, diff } from 'skatejs-dom-diff';

function done (instructions) {
patch(instructions);
}
diff(

source

,

target

, { done });
```

#### `merge(source, target, options)`

For `done()`, it's passed in the same exact way. The only difference is that it's called after the patch is performed but it's still passed the instructions that were performed by the patch algorithm.

```js
/** @jsx h */
import { h, merge } from 'skatejs-dom-diff';

function done (instructions) {
// The DOM has been updated, do what you want here.
}
merge(

source

,

target

, { done });
```

#### `render(source, target, options)`

And for `render()`, it is the same as the `merge()` function. So once the vDOM is rendered and DOM is patched, `done()` is called with the instructions that were performed.

```js
import { h, render } from 'skatejs-dom-diff';

function done (instructions) {
// Renering and patching is done...
}
const root = document.createElement('div');
const doRender = render((root) => (

{root.test}

));

div.test = 'initial text';
doRender(div, done);

div.test = 'updated text';
doRender(div, done);
```