Une bibliothèque DOM virtuelle en mettant l'accent sur la simplicité, la modularité, les fonctionnalités puissantes et les performances.
Merci à Browserstack pour avoir accès à leurs excellents outils de test de croisement.
Anglais | 简体中文 | hindi
Virtual Dom est génial. Il nous permet d'exprimer le point de vue de notre application en fonction de son état. Mais les solutions existantes étaient beaucoup trop gonflées, trop lentes, manquaient de fonctionnalités, avaient une API biaisée vers la POO et / ou manquait les fonctionnalités dont j'avais besoin.
Snabbdom se compose d'un noyau extrêmement simple, performant et extensible qui n'est que ≈ 200 sloc. Il offre une architecture modulaire avec une riche fonctionnalité pour les extensions via des modules personnalisés. Pour garder le noyau simple, toutes les fonctionnalités non essentielles sont déléguées aux modules.
Vous pouvez mouler Snabbdom dans tout ce que vous désirez! Choisissez, choisissez et personnalisez les fonctionnalités souhaitées. Alternativement, vous pouvez simplement utiliser les extensions par défaut et obtenir une bibliothèque DOM virtuelle avec des performances élevées, une petite taille et toutes les fonctionnalités énumérées ci-dessous.
h Fonction H pour créer facilement des nœuds DOM virtuels.h import {
init ,
classModule ,
propsModule ,
styleModule ,
eventListenersModule ,
h
} from "snabbdom" ;
const patch = init ( [
// Init patch function with chosen modules
classModule , // makes it easy to toggle classes
propsModule , // for setting properties on DOM elements
styleModule , // handles styling on elements with support for animations
eventListenersModule // attaches event listeners
] ) ;
const container = document . getElementById ( "container" ) ;
const vnode = h (
"div#container.two.classes" ,
{ on : { click : ( ) => console . log ( "div clicked" ) } } ,
[
h ( "span" , { style : { fontWeight : "bold" } } , "This is bold" ) ,
" and this is just normal text" ,
h ( "a" , { props : { href : "/foo" } } , "I'll take you places!" )
]
) ;
// Patch into empty DOM element – this modifies the DOM as a side effect
patch ( container , vnode ) ;
const newVnode = h (
"div#container.two.classes" ,
{ on : { click : ( ) => console . log ( "updated div clicked" ) } } ,
[
h (
"span" ,
{ style : { fontWeight : "normal" , fontStyle : "italic" } } ,
"This is now italic type"
) ,
" and this is still just normal text" ,
h ( "a" , { props : { href : "/bar" } } , "I'll take you places!" )
]
) ;
// Second `patch` invocation
patch ( vnode , newVnode ) ; // Snabbdom efficiently updates the old view to the new state initpatchhfragment (expérimental)toVNodeinitinsertremovedestroyremovedestroyLe noyau de Snabbdom ne fournit que les fonctionnalités les plus essentielles. Il est conçu pour être aussi simple que possible tout en étant rapide et extensible.
init Le noyau expose une seule fonction une seule init . Cette init prend une liste de modules et renvoie une fonction patch qui utilise l'ensemble spécifié de modules.
import { classModule , styleModule } from "snabbdom" ;
const patch = init ( [ classModule , styleModule ] ) ;patch La fonction patch renvoyée par init prend deux arguments. Le premier est un élément DOM ou un VNode représentant la vue actuelle. Le second est un VNode représentant la nouvelle vue mise à jour.
Si un élément DOM avec un parent est passé, newVnode sera transformé en nœud DOM et l'élément passé sera remplacé par le nœud Dom créé. Si un ancien Vnode est passé, Snabbdom le modifie efficacement pour correspondre à la description dans le nouveau VNode.
Tout vieux Vnode passé doit être le VNode résultant d'un appel précédent à patch . Ceci est nécessaire car Snabbdom stocke les informations dans le VNode. Cela permet d'implémenter une architecture plus simple et plus performante. Cela évite également la création d'un nouvel arbre Vnode.
patch ( oldVnode , newVnode ) ; Bien qu'il n'y ait aucune API spécifiquement pour supprimer un arbre VNode de son élément de point de montage, une façon de presque y parvenir est de fournir un commentaire VNode comme deuxième argument à patch , tel que:
patch (
oldVnode ,
h ( "!" , {
hooks : {
post : ( ) => {
/* patch complete */
}
}
} )
) ;Bien sûr, il y a encore un seul nœud de commentaire au point de montage.
h Il est recommandé d'utiliser h pour créer des vnodes. Il accepte une balise / sélecteur sous forme de chaîne, un objet de données facultatif et une chaîne facultative ou un tableau d'enfants.
import { h } from "snabbdom" ;
const vnode = h ( "div#container" , { style : { color : "#000" } } , [
h ( "h1.primary-title" , "Headline" ) ,
h ( "p" , "A paragraph" )
] ) ;fragment (expérimental)ATTENTION: Cette fonctionnalité est actuellement expérimentale et doit être optée. Son API peut être modifiée sans une bosse de version majeure.
const patch = init ( modules , undefined , {
experimental : {
fragments : true
}
} ) ;Crée un nœud virtuel qui sera converti en un fragment de document contenant les enfants donnés.
import { fragment , h } from "snabbdom" ;
const vnode = fragment ( [ "I am" , h ( "span" , [ " a" , " fragment" ] ) ] ) ;toVNodeConvertit un nœud DOM en un nœud virtuel. Particulièrement bon pour le correctif sur le contenu HTML généré par le côté préexistant.
import {
init ,
styleModule ,
attributesModule ,
h ,
toVNode
} from "snabbdom" ;
const patch = init ( [
// Initialize a `patch` function with the modules used by `toVNode`
attributesModule // handles attributes from the DOM node
datasetModule , // handles `data-*` attributes from the DOM node
] ) ;
const newVNode = h ( "div" , { style : { color : "#000" } } , [
h ( "h1" , "Headline" ) ,
h ( "p" , "A paragraph" ) ,
h ( "img" , { attrs : { src : "sunrise.png" , alt : "morning sunrise" } } )
] ) ;
patch ( toVNode ( document . querySelector ( ".container" ) ) , newVNode ) ;Les crochets sont un moyen de s'accrocher au cycle de vie des nœuds DOM. Snabbdom propose une riche sélection de crochets. Les crochets sont utilisés à la fois par des modules pour étendre Snabbdom et dans le code normal pour exécuter du code arbitraire aux points souhaités dans la durée de vie d'un nœud virtuel.
| Nom | Déclenché quand | Arguments au rappel |
|---|---|---|
pre | Le processus de patch commence | aucun |
init | Un vnode a été ajouté | vnode |
create | Un élément DOM a été créé sur la base d'un vnode | emptyVnode, vnode |
insert | Un élément a été inséré dans le DOM | vnode |
prepatch | Un élément est sur le point d'être corrigé | oldVnode, vnode |
update | Un élément est mis à jour | oldVnode, vnode |
postpatch | Un élément a été corrigé | oldVnode, vnode |
destroy | Un élément est directement ou indirectement enlevé | vnode |
remove | Un élément est directement supprimé du DOM | vnode, removeCallback |
post | Le processus de correctif est effectué | aucun |
Les crochets suivants sont disponibles pour les modules: pre , create , update , destroy , remove , post .
Les crochets suivants sont disponibles dans la propriété hook des éléments individuels: init , create , insert , prepatch , update , postpatch , destroy , remove .
Pour utiliser des crochets, passez-les comme un champ d'objet pour hook de l'argument de l'objet de données.
h ( "div.row" , {
key : movie . rank ,
hook : {
insert : ( vnode ) => {
movie . elmHeight = vnode . elm . offsetHeight ;
}
}
} ) ; initCe crochet est invoqué pendant le processus de patch lorsqu'un nouveau nœud virtuel a été trouvé. Le crochet est appelé avant que Snabbdom n'ait traité le nœud de quelque manière que ce soit. C'est-à-dire avant qu'il n'ait créé un nœud DOM basé sur le VNode.
insertCe crochet est invoqué une fois que l'élément DOM d'un VNode a été inséré dans le document et que le reste du cycle de patch est terminé. Cela signifie que vous pouvez effectuer des mesures DOM (comme utiliser GetBoundingClientRect dans ce crochet en toute sécurité, sachant qu'aucun éléments ne sera modifié par la suite qui pourrait affecter la position des éléments insérés.
remove Vous permet de vous accrocher à la suppression d'un élément. Le crochet est appelé une fois qu'un vnode doit être retiré du DOM. La fonction de gestion reçoit à la fois le VNode et un rappel. Vous pouvez contrôler et retarder le retrait avec le rappel. Le rappel doit être invoqué une fois le crochet terminé en faisant ses activités, et l'élément ne sera supprimé qu'une fois que tous les crochets remove ont invoqué leur rappel.
Le crochet n'est déclenché que lorsqu'un élément doit être retiré de son parent - pas s'il s'agit de l'enfant d'un élément qui est supprimé. Pour cela, voyez le crochet destroy .
destroyCe crochet est invoqué sur un nœud virtuel lorsque son élément Dom est supprimé du DOM ou si son parent est supprimé du DOM.
Pour voir la différence entre ce crochet et le crochet remove , considérez un exemple.
const vnode1 = h ( "div" , [ h ( "div" , [ h ( "span" , "Hello" ) ] ) ] ) ;
const vnode2 = h ( "div" , [ ] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ; Ici, destroy est déclenché à la fois pour l'élément div intérieur et l'élément span qu'il contient. remove , en revanche, n'est déclenché que sur l'élément div car il est le seul élément détaché de son parent.
Vous pouvez, par exemple, utiliser remove pour déclencher une animation lorsqu'un élément est en cours de suppression et utiliser le crochet destroy pour animer en outre la disparition des enfants de l'élément supprimé.
Les modules fonctionnent en enregistrant les auditeurs mondiaux pour les crochets. Un module est simplement un dictionnaire mappant des noms de crochets aux fonctions.
const myModule = {
create : ( oldVnode , vnode ) => {
// invoked whenever a new virtual node is created
} ,
update : ( oldVnode , vnode ) => {
// invoked whenever a virtual node is updated
}
} ;Avec ce mécanisme, vous pouvez facilement augmenter le comportement de Snabbdom. Pour la démonstration, jetez un œil aux implémentations des modules par défaut.
Ceci décrit les modules de base. Tous les modules sont facultatifs. Les exemples de JSX supposent que vous utilisez le jsx Pragma fourni par cette bibliothèque.
Le module de classe offre un moyen facile de basculer dynamiquement les classes sur les éléments. Il s'attend à un objet dans la propriété de données class . L'objet doit cartographier les noms de classe aux booléens qui indiquent si la classe doit rester ou non sur le VNode.
h ( "a" , { class : { active : true , selected : false } } , "Toggle" ) ; Dans JSX, vous pouvez utiliser class comme ceci:
< div class = { { foo : true , bar : true } } />
// Renders as: <div class="foo bar"></div>Vous permet de définir des propriétés sur les éléments DOM.
h ( "a" , { props : { href : "/foo" } } , "Go to Foo" ) ; Dans JSX, vous pouvez utiliser props comme ceci:
< input props = { { name : "foo" } } />
// Renders as: <input name="foo" /> with input.name === "foo"Les propriétés ne peuvent être définies que. Non supprimé. Même si les navigateurs permettent l'addition et la suppression des propriétés personnalisées, la suppression ne sera pas tentée par ce module. Cela a du sens, car les propriétés DOM natives ne peuvent pas être supprimées. Et si vous utilisez des propriétés personnalisées pour stocker des valeurs ou référencer des objets sur le DOM, veuillez envisager d'utiliser plutôt des attributs de données. Peut-être via le module de jeu de données.
Identique aux accessoires, mais à définir des attributs au lieu de propriétés sur les éléments DOM.
h ( "a" , { attrs : { href : "/foo" } } , "Go to Foo" ) ; Dans JSX, vous pouvez utiliser attrs comme celle-ci:
< div attrs = { { "aria-label" : "I'm a div" } } />
// Renders as: <div aria-label="I'm a div"></div> Des attributs sont ajoutés et mis à jour à l'aide de setAttribute . Dans le cas d'un attribut qui avait été précédemment ajouté / défini et n'est plus présent dans l'objet attrs , il est supprimé de la liste d'attribut de l'élément DOM à l'aide removeAttribute .
Dans le cas des attributs booléens (par exemple disabled , hidden , selected ...), la signification ne dépend pas de la valeur d'attribut ( true ou false ) mais dépend plutôt de la présence / absence de l'attribut lui-même dans l'élément DOM. Ces attributs sont gérés différemment par le module: si un attribut booléen est défini sur une valeur Falsy ( 0 , -0 , null , false , NaN , undefined ou la chaîne vide ( "" )), alors l'attribut sera supprimé de la liste d'attribut de l'élément DOM.
Vous permet de définir des attributs de données personnalisés ( data-* ) sur les éléments DOM. Ceux-ci sont ensuite accessibles avec la propriété htmlelement.dataset.
h ( "button" , { dataset : { action : "reset" } } , "Reset" ) ; Dans JSX, vous pouvez utiliser dataset comme ceci:
< div dataset = { { foo : "bar" } } />
// Renders as: <div data-foo="bar"></div>Le module de style est pour rendre votre HTML lisse et animer en douceur. À la base, il vous permet de définir les propriétés CSS sur les éléments.
h (
"span" ,
{
style : {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
}
} ,
"Say my name, and every colour illuminates"
) ; Dans JSX, vous pouvez utiliser style comme ceci:
< div
style = { {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
} }
/>
// Renders as: <div style="border: 1px solid #bada55; color: #c0ffee; font-weight: bold"></div> Les propriétés personnalisées CSS (variables AKA CSS) sont prises en charge, elles doivent être préfixées avec --
h (
"div" ,
{
style : { "--warnColor" : "yellow" }
} ,
"Warning"
) ; Vous pouvez spécifier les propriétés comme étant retardées. Chaque fois que ces propriétés changent, la modification n'est appliquée qu'après la trame suivante.
h (
"span" ,
{
style : {
opacity : "0" ,
transition : "opacity 1s" ,
delayed : { opacity : "1" }
}
} ,
"Imma fade right in!"
) ;Cela facilite l'animation de déclarativement l'entrée des éléments.
La all valeur de transition-property n'est pas prise en charge.
remove Les styles définis dans la propriété remove prendront effet une fois que l'élément sera sur le point d'être supprimé du DOM. Les styles appliqués doivent être animés avec des transitions CSS. Ce n'est qu'une fois que tous les styles sont terminés l'animation que l'élément sera supprimé du DOM.
h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
remove : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ;Cela facilite l'animation de déclarativement la suppression des éléments.
La all valeur de transition-property n'est pas prise en charge.
destroy h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
destroy : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ; La all valeur de transition-property n'est pas prise en charge.
Le module des écouteurs d'événements offre des capacités puissantes pour attacher des auditeurs d'événements.
Vous pouvez attacher une fonction à un événement sur un VNode en fournissant un objet on une propriété correspondant au nom de l'événement que vous souhaitez écouter. La fonction sera appelée lorsque l'événement se produira et sera transmis à l'objet de l'événement qui lui appartient.
function clickHandler ( ev ) {
console . log ( "got clicked" ) ;
}
h ( "div" , { on : { click : clickHandler } } ) ; Dans JSX, vous pouvez utiliser on ceci:
< div on = { { click : clickHandler } } />Snabbdom permet d'échanger des gestionnaires d'événements entre les rendus. Cela se produit sans toucher réellement les gestionnaires d'événements attachés au DOM.
Notez cependant que vous devez être prudent lorsque vous partagez des gestionnaires d'événements entre VNodes , en raison de la technique que ce module utilise pour éviter les gestionnaires d'événements de reconstitution au DOM. (Et en général, le partage de données entre VNodes n'est pas garanti pour fonctionner, car les modules sont autorisés à muter les données données).
En particulier, vous ne devriez pas faire quelque chose comme ceci:
// Does not work
const sharedHandler = {
change : ( e ) => {
console . log ( "you chose: " + e . target . value ) ;
}
} ;
h ( "div" , [
h ( "input" , {
props : { type : "radio" , name : "test" , value : "0" } ,
on : sharedHandler
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "1" } ,
on : sharedHandler
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "2" } ,
on : sharedHandler
} )
] ) ; Pour de nombreux cas de ce type, vous pouvez utiliser des gestionnaires basés sur des tableaux à la place (décrits ci-dessus). Alternativement, assurez-vous simplement que chaque nœud est passé unique on les valeurs:
// Works
const sharedHandler = ( e ) => {
console . log ( "you chose: " + e . target . value ) ;
} ;
h ( "div" , [
h ( "input" , {
props : { type : "radio" , name : "test" , value : "0" } ,
on : { change : sharedHandler }
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "1" } ,
on : { change : sharedHandler }
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "2" } ,
on : { change : sharedHandler }
} )
] ) ; SVG fonctionne simplement lors de l'utilisation de la fonction h pour créer des nœuds virtuels. Les éléments SVG sont créés automatiquement avec les espaces de noms appropriés.
const vnode = h ( "div" , [
h ( "svg" , { attrs : { width : 100 , height : 100 } } , [
h ( "circle" , {
attrs : {
cx : 50 ,
cy : 50 ,
r : 40 ,
stroke : "green" ,
"stroke-width" : 4 ,
fill : "yellow"
}
} )
] )
] ) ;Voir aussi l'exemple SVG et l'exemple du carrousel SVG.
Certains navigateurs (comme IE <= 11) ne prennent pas en charge la propriété classList dans les éléments SVG. Étant donné que le module de classe utilise en interne classList , il ne fonctionnera pas dans ce cas à moins que vous n'utilisiez un polyfill classlist. (Si vous ne souhaitez pas utiliser un polyfill, vous pouvez utiliser l'attribut class avec le module Attributs ).
La fonction thunk prend un sélecteur, une clé pour identifier un thunk, une fonction qui renvoie un VNode et une quantité variable de paramètres d'état. S'il est invoqué, la fonction de rendu recevra les arguments de l'État.
thunk(selector, key, renderFn, [stateArguments])
Le renderFn n'est invoqué que si le renderFn est modifié ou que la longueur du tableau [stateArguments] ou si ses éléments sont modifiés.
La key est facultative. Il doit être fourni lorsque le selector n'est pas unique parmi les frères et sœurs Thunks. Cela garantit que le thunk est toujours correctement apparié lors de la diffusion.
Les thunks sont une stratégie d'optimisation qui peut être utilisée lorsque l'on traite des données immuables.
Considérez une fonction simple pour créer un nœud virtuel basé sur un nombre.
function numberView ( n ) {
return h ( "div" , "Number is: " + n ) ;
} La vue dépend uniquement de n . Cela signifie que si n est inchangé, la création du nœud DOM virtuel et le corriger contre l'ancien VNode est un gaspillage. Pour éviter les frais généraux, nous pouvons utiliser la fonction d'assistance thunk .
function render ( state ) {
return thunk ( "num" , numberView , [ state . number ] ) ;
} Au lieu d'invoquer réellement la fonction numberView cela ne placera qu'un vnode factice dans l'arborescence virtuelle. Lorsque Snabbdom patchs ce VNODE MANDE contre un VNode précédent, il comparera la valeur de n . Si n est inchangé, il réutilisera simplement l'ancien VNode. Cela évite de recréer la vue du nombre et le processus Diff.
La fonction de vue ici n'est qu'un exemple. En pratique, les thunks ne sont pertinents que si vous rendez une vue compliquée qui prend un temps de calcul important à générer.
Notez que les fragments JSX sont toujours expérimentaux et doivent être optés. Voir la section fragment pour plus de détails.
Ajoutez les options suivantes à votre tsconfig.json :
{
"compilerOptions" : {
"jsx" : " react " ,
"jsxFactory" : " jsx " ,
"jsxFragmentFactory" : " Fragment "
}
} Assurez-vous ensuite d'utiliser l'extension du fichier .tsx et d'importer la fonction jsx et la fonction Fragment en haut du fichier:
import { Fragment , jsx , VNode } from "snabbdom" ;
const node : VNode = (
< div >
< span > I was created with JSX </ span >
</ div >
) ;
const fragment : VNode = (
< >
< span > JSX fragments </ span >
are experimentally supported
</ >
) ;Ajoutez les options suivantes à votre configuration Babel:
{
"plugins" : [
[
" @babel/plugin-transform-react-jsx " ,
{
"pragma" : " jsx " ,
"pragmaFrag" : " Fragment "
}
]
]
} Importez ensuite la fonction jsx et la fonction Fragment en haut du fichier:
import { Fragment , jsx } from "snabbdom" ;
const node = (
< div >
< span > I was created with JSX </ span >
</ div >
) ;
const fragment = (
< >
< span > JSX fragments </ span >
are experimentally supported
</ >
) ; Propriétés
La propriété sel spécifie l'élément HTML du VNODE, éventuellement son id préfixé par un # , et zéro ou plus de classes chacune préfixées par a . . La syntaxe est inspirée par les sélecteurs CSS. Voici quelques exemples:
div#container.bar.baz - un élément div avec le container ID et la bar des classes et baz .li - un élément li sans id ni classes.button.alert.primary - élément button avec les deux classes alert et primary . Le sélecteur est censé être statique , c'est-à-dire qu'il ne devrait pas changer au cours de la durée de vie de l'élément. Pour définir un id dynamique, utilisez le module d'accessoires et pour définir les classes dynamiques, utilisez le module de classe.
Étant donné que le sélecteur est statique, Snabbdom l'utilise dans le cadre d'une identité VNodes. Par exemple, si les deux enfants vnodes
[ h ( "div#container.padding" , children1 ) , h ( "div.padding" , children2 ) ] ;sont corrigés contre
[ h ( "div#container.padding" , children2 ) , h ( "div.padding" , children1 ) ] ;Ensuite, Snabbdom utilise le sélecteur pour identifier les VNodes et les réorganiser dans l'arborescence DOM au lieu de créer un nouvel élément DOM. Cette utilisation de sélecteurs évite la nécessité de spécifier les clés dans de nombreux cas.
La propriété .data d'un nœud virtuel est l'endroit idéal pour ajouter des informations pour les modules pour accéder et manipuler l'élément DOM réel lors de sa création; Ajoutez des styles, des classes CSS, des attributs, etc.
L'objet de données est le deuxième paramètre (facultatif) de h()
Par exemple h('div', {props: {className: 'container'}}, [...]) produira un nœud virtuel avec
( {
props : {
className : "container"
}
} ) ; comme son objet .data .
La propriété .children d'un nœud virtuel est le troisième paramètre (facultatif) de h() pendant la création. .children sont simplement un tableau de nœuds virtuels qui doivent être ajoutés en tant qu'enfants du nœud Parent Dom lors de la création.
Par exemple h('div', {}, [ h('h1', {}, 'Hello, World') ]) créera un nœud virtuel avec
[
{
sel : "h1" ,
data : { } ,
children : undefined ,
text : "Hello, World" ,
elm : Element ,
key : undefined
}
] ; comme sa .children .
La propriété .text est créée lorsqu'un nœud virtuel est créé avec un seul enfant qui possède du texte et ne nécessite que document.createTextNode() à utiliser.
Par exemple: h('h1', {}, 'Hello') créera un nœud virtuel avec Hello comme sa propriété .text .
La propriété .elm d'un nœud virtuel est un pointeur vers le nœud Dom réel créé par Snabbdom. Cette propriété est très utile pour effectuer des calculs dans les crochets ainsi que les modules.
La propriété .key est créée lorsqu'une clé est fournie à l'intérieur de votre objet .data . La propriété .key est utilisée pour garder les pointeurs vers les nœuds DOM qui existaient auparavant pour éviter les recréer s'ils sont inutiles. Ceci est très utile pour des choses comme la réorganisation de la liste. Une clé doit être une chaîne ou un nombre pour permettre une recherche appropriée car elle est stockée en interne en tant que paire de touches / valeur à l'intérieur d'un objet, où .key est la clé et la valeur est la propriété .elm créée.
S'il est fourni, la propriété .key
Par exemple: h('div', {key: 1}, []) créera un objet de nœud virtuel avec une propriété .key avec la valeur de 1 .
Snabbdom est une bibliothèque DOM virtuelle de bas niveau. Il n'est pas opposé en ce qui concerne la façon dont vous devez structurer votre application.
Voici quelques approches pour créer des applications avec Snabbdom.
Assurez-vous de le partager si vous créez une application d'une autre manière en utilisant Snabbdom.
Les packages liés à Snabbdom doivent être tagués avec le mot clé snabbdom et publiés sur NPM. Ils peuvent être trouvés en utilisant les keywords:snabbdom .
Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node':
The node before which the new node is to be inserted is not a child of this node.
La raison de cette erreur est la réutilisation des VNodes entre les correctifs (voir l'exemple de code), Snabbdom stocke les nœuds DOM réels à l'intérieur des nœuds DOM virtuels qui lui sont passés sous forme d'amélioration des performances, de sorte que la réutilisation des nœuds entre les correctifs n'est pas prise en charge.
const sharedNode = h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ] )
] ) ;
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ sharedNode ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ;Vous pouvez résoudre ce problème en créant une copie superficielle de l'objet (ici avec la syntaxe de propagation de l'objet):
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ { ... sharedNode } ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;Une autre solution serait d'envelopper des vnodes partagés dans une fonction d'usine:
const sharedNode = ( ) => h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ( ) ] )
] ) ; Les demandes de traction sur lesquelles la communauté peut se soucier de fournir des commentaires devraient être fusionnées après la fourniture d'une telle opportunité de quelques jours.