Un DOM virtual ligero al estilo de Snabbdom. Representa tu interfaz con objetos JavaScript llanos (los VNode), compara un árbol viejo con uno nuevo y aplica al DOM real solo las diferencias.
init() arma el reconciliador y devuelve una función patch. Los módulos que vienen incluidos (class / props / attrs / style / events) se registran solos.
patch(oldVnode, newVnode) monta un árbol (cuando oldVnode es un elemento real del DOM) o compara dos árboles de vnodes y actualiza el DOM sobre la marcha.
h(sel, dataOrChildren?, children?) es la ayuda de hyperscript que construye los VNode.
Nota: en esta implementación init()no recibe argumentos: el juego de módulos es fijo y se registra por dentro, así que no hace falta pasarle a init cada *Module por separado. Se exportan para consultarlos e inspeccionarlos.
import { init, h } from 'ranuts/vnode';// init() devuelve una función `patch`.// Los módulos incluidos (class, props, attrs, style, events) se registran solos.const patch = init();const container = document.getElementById('app');// Construye un árbol de vnodeslet vnode = h('div#app.container', { style: { color: 'red' } }, [ h('h1', 'Hello vnode'), h('button', { on: { click: () => console.log('clicked') } }, 'Click me'),]);// Primer dibujado: pasa un elemento real del DOM como vnode viejo para montar dentro de élpatch(container, vnode);// Más tarde: construye el árbol actualizado y aplica sobre él el vnode anterior.// Al DOM solo llegan las diferencias (texto, estilo, escuchadores).const newVnode = h('div#app.container', { style: { color: 'green' } }, [ h('h1', 'Hello again'), h('button', { on: { click: () => console.log('clicked') } }, 'Updated'),]);patch(vnode, newVnode);vnode = newVnode; // guarda el último árbol para el siguiente patch
// solo la etiquetah('div');// etiqueta + datah('div', { class: { active: true } });// etiqueta + un único hijo de textoh('span', 'hello');// etiqueta + array de hijosh('ul', [h('li', 'one'), h('li', 'two')]);// etiqueta + data + hijosh('a', { attrs: { href: '/home' } }, 'Home');// Los selectores al estilo CSS fijan el id y las clasesh('div#main.card.large', 'content'); // <div id="main" class="card large">content</div>// El espacio de nombres de SVG se aplica solo cuando el selector empieza por "svg"h('svg', { attrs: { width: 100, height: 100 } }, [h('circle', { attrs: { cx: 50, cy: 50, r: 40 } })]);
La devuelve init(). En la primera llamada, pasa un Element real del DOM como oldVnode para montar el árbol dentro de él. En las siguientes, pasa el VNode anterior para comparar y actualizar sobre la marcha. Devuelve el nuevo VNode, que guardas como valor «viejo» para la llamada siguiente.
Propiedades del DOM asignadas con elm[key] = value
Record<string, any>
propsModule
attrs
Atributos HTML puestos con setAttribute (true y false ponen y quitan el atributo)
Record<string, string | number | boolean>
attributesModule
class
Clases condicionales: una correspondencia name → boolean
Record<string, boolean>
classModule
style
Estilos en línea: una correspondencia name → value (las claves --var pasan a variables CSS)
Record<string, any>
styleModule
on
Escuchadores de eventos: event → handler (o un array de manejadores)
Record<string, Function | Function[]>
eventListenersModule
key
Identidad estable que usa el algoritmo de comparación para emparejar y reordenar los hijos
string | number
(el núcleo de la comparación)
ns
URI del espacio de nombres (se pone sola en los subárboles SVG)
string
(el núcleo de la comparación)
hook
Ganchos de ciclo de vida por vnode (Hooks)
Hooks
(solo como tipo: véase la nota)
Nota: hook y el tipo Hooks forman parte de la superficie pública de tipos. Esta implementación recortada mueve el DOM a través del ciclo de vida de los módulos (create / update / destroy); el bucle de patch actual no llama a los data.hook de cada vnode.
Solo navegador.ranuts/vnode toca document y las API del DOM; impórtalo en código de navegador, no en Node.
Guarda el último vnode.patch devuelve el nuevo VNode. Guárdalo y pásalo como oldVnode en la siguiente actualización, para que las diferencias se calculen contra el árbol vigente.
En un VNode, text y children se excluyen entre sí: un nodo es o bien un nodo de texto, o bien un elemento con hijos.
Usa key en las listas. Al dibujar listas que cambian, dale a los hermanos valores de key estables, para que la comparación pueda emparejar y reordenar nodos en vez de rehacerlos.