Eine virtuelle DOM -Bibliothek mit Schwerpunkt auf Einfachheit, Modularität, leistungsstarke Merkmale und Leistung.
Vielen Dank an BrowsStack für den Zugang zu ihren großartigen Cross-Browser-Testwerkzeugen.
Englisch | 简体中文 | Hindi
Virtual Dom ist großartig. Es ermöglicht uns, die Ansicht unserer Anwendung als Funktion des Zustands auszudrücken. Die vorhandenen Lösungen waren jedoch viel zu aufgebläht, zu langsam, fehlten Merkmale, hatten eine API, die in Richtung OOP voreingenommen war, und/oder fehlten Merkmale, die ich brauchte.
Snabbdom besteht aus einem extrem einfachen, leistungsfähigen und erweiterbaren Kern, der nur ≈ 200 Sloc ist. Es bietet eine modulare Architektur mit reichhaltigen Funktionen für Erweiterungen durch benutzerdefinierte Module. Um den Kern einfach zu halten, wird alle nicht wichtigen Funktionen an Module delegiert.
Sie können Snabbdom zu dem formen, was Sie sich wünschen! Wählen Sie die gewünschten Funktionen aus, wählen Sie und passen Sie ihn an. Alternativ können Sie nur die Standardverlängerungen verwenden und eine virtuelle DOM -Bibliothek mit hoher Leistung, geringer Größe und allen unten aufgeführten Funktionen erhalten.
h Funktion zum einfachen Erstellen virtueller Dom -Knoten.h -Helfer. 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 (experimentell)toVNodeinit -Hakeninsertremovedestroy Hakenremovedestroy festlegenDer Kern von Snabbdom liefert nur die wichtigste Funktionalität. Es ist so einfach wie möglich ausgelegt, während es immer noch schnell und ausziehbar ist.
init Der Kern enthält nur eine einzige Funktion init . Dieser init enthält eine Liste von Modulen und gibt eine patch -Funktion zurück, die den angegebenen Satz von Modulen verwendet.
import { classModule , styleModule } from "snabbdom" ;
const patch = init ( [ classModule , styleModule ] ) ;patch Die durch init zurückgegebene patch -Funktion nimmt zwei Argumente vor. Das erste ist ein DOM -Element oder ein Vnode, das die aktuelle Ansicht darstellt. Der zweite ist ein VNode, der die neue, aktualisierte Ansicht darstellt.
Wenn ein DOM -Element mit einem übergeordneten übergeben wird, wird newVnode in einen DOM -Knoten umgewandelt und das übergebene Element wird durch den erstellten DOM -Knoten ersetzt. Wenn ein alter VNODE übergeben wird, wird Snabbdom effizient so geändert, dass er der Beschreibung im neuen VNODE entspricht.
Jeder alte VNode, der übergeben wurde, muss der resultierende VNode aus einem vorherigen Anruf zum patch sein. Dies ist notwendig, da Snabbdom Informationen im VNODE speichert. Dies ermöglicht es, eine einfachere und leistungsfähigere Architektur zu implementieren. Dies vermeidet auch die Schaffung eines neuen alten Vnode -Baumes.
patch ( oldVnode , newVnode ) ; Während es keine API gibt, um einen Vnode -Baum aus seinem Mount -Point -Element zu entfernen, ist eine Möglichkeit, dies fast zu erreichen, einen Kommentar -VNODE als zweites Argument zum patch , z. B.:
patch (
oldVnode ,
h ( "!" , {
hooks : {
post : ( ) => {
/* patch complete */
}
}
} )
) ;Natürlich gibt es am Mountspunkt noch einen einzigen Kommentarknoten.
h Es wird empfohlen, dass Sie h verwenden, um VNODES zu erstellen. Es akzeptiert einen Tag/Selector als Zeichenfolge, ein optionales Datenobjekt und eine optionale Zeichenfolge oder ein Array von Kindern.
import { h } from "snabbdom" ;
const vnode = h ( "div#container" , { style : { color : "#000" } } , [
h ( "h1.primary-title" , "Headline" ) ,
h ( "p" , "A paragraph" )
] ) ;fragment (experimentell)VORSICHT: Diese Funktion ist derzeit experimentell und muss angemeldet werden. Die API kann ohne eine größere Versionsbeule geändert werden.
const patch = init ( modules , undefined , {
experimental : {
fragments : true
}
} ) ;Erstellt einen virtuellen Knoten, der in ein Dokumentfragment umgewandelt wird, das die angegebenen Kinder enthält.
import { fragment , h } from "snabbdom" ;
const vnode = fragment ( [ "I am" , h ( "span" , [ " a" , " fragment" ] ) ] ) ;toVNodeKonvertiert einen DOM -Knoten in einen virtuellen Knoten. Besonders gut zum Patching über bereits bestehende, serverseitige HTML-Inhalte.
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 ) ;Haken sind ein Weg, um sich in den Lebenszyklus von Dom -Knoten einzuschließen. Snabbdom bietet eine reiche Auswahl an Haken. Hooks werden sowohl von Modulen als auch von Modulen verwendet, um Snabbdom zu erweitern, als auch im normalen Code zur Ausführung beliebiger Code an gewünschten Punkten in der Lebensdauer eines virtuellen Knotens.
| Name | Ausgelöst wann | Argumente zum Rückruf |
|---|---|---|
pre | Der Patch -Prozess beginnt | keiner |
init | Ein Vnode wurde hinzugefügt | vnode |
create | Ein DOM -Element wurde basierend auf einem VNODE erstellt | emptyVnode, vnode |
insert | Ein Element wurde in die DOM eingefügt | vnode |
prepatch | Ein Element ist im Begriff, gepatcht zu werden | oldVnode, vnode |
update | Ein Element wird aktualisiert | oldVnode, vnode |
postpatch | Ein Element wurde gepatcht | oldVnode, vnode |
destroy | Ein Element wird direkt oder indirekt entfernt | vnode |
remove | Ein Element wird direkt aus dem DOM entfernt | vnode, removeCallback |
post | Der Patch -Prozess erfolgt | keiner |
Die folgenden Haken stehen für Module zur Verfügung: pre , create , update , destroy , remove , post .
Die folgenden Haken sind in der hook einzelner Elemente erhältlich: init , create , insert , prepatch , update , postpatch , destroy , remove .
Um Hooks zu verwenden, übergeben Sie sie als Objekt an das Feld des hook .
h ( "div.row" , {
key : movie . rank ,
hook : {
insert : ( vnode ) => {
movie . elmHeight = vnode . elm . offsetHeight ;
}
}
} ) ; init -HakenDieser Haken wird während des Patch -Prozesses aufgerufen, wenn ein neuer virtueller Knoten gefunden wurde. Der Haken wird aufgerufen, bevor Snabbdom den Knoten in irgendeiner Weise verarbeitet hat. Dh, bevor es einen DOM -Knoten erstellt hat, basierend auf dem VNode.
insertDieser Haken wird aufgerufen, sobald das DOM -Element für einen Vnode in das Dokument eingefügt wurde und der Rest des Patch -Zyklus erfolgt. Dies bedeutet, dass Sie DOM -Messungen durchführen können (z. B. die Verwendung von GetBoundingClientRect in diesem Haken sicher, wenn Sie wissen, dass danach keine Elemente geändert werden, die die Position der eingefügten Elemente beeinflussen können.
remove Ermöglicht es Ihnen, ein Element zu entfernen. Der Haken wird aufgerufen, sobald ein Vnode aus dem DOM entfernt werden soll. Die Handhabungsfunktion empfängt sowohl den VNode als auch einen Rückruf. Sie können die Entfernung mit dem Rückruf steuern und verzögern. Der Rückruf sollte aufgerufen werden, sobald der Haken abgeschlossen ist, und das Element wird nur entfernt, sobald alle remove auf ihren Rückruf aufgerufen haben.
Der Haken wird nur ausgelöst, wenn ein Element von seinem Elternteil entfernt werden soll - nicht, wenn es das Kind eines Elements ist, das entfernt wird. Dafür sehen Sie den destroy .
destroy HakenDieser Haken wird auf einem virtuellen Knoten aufgerufen, wenn sein DOM -Element aus dem DOM entfernt wird oder wenn sein übergeordnetes übergeordnet ist.
Betrachten Sie ein Beispiel, um den Unterschied zwischen diesem Haken und dem Haken remove .
const vnode1 = h ( "div" , [ h ( "div" , [ h ( "span" , "Hello" ) ] ) ] ) ;
const vnode2 = h ( "div" , [ ] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ; Hier wird destroy sowohl für das innere div -Element als auch für das span -Element ausgelöst, das es enthält. remove andererseits nur im div -Element ausgelöst, da es das einzige Element ist, das von seinem Elternteil abgelöst wird.
Sie können beispielsweise remove verwenden, um eine Animation auszulösen, wenn ein Element entfernt wird, und den destroy verwenden, um das Verschwinden der Kinder des entfernten Elements zusätzlich zu belasten.
Module funktionieren, indem sie globale Zuhörer für Hooks registrieren. Ein Modul ist einfach ein Wörterbuch -Mapping -Hook -Namen zu Funktionen.
const myModule = {
create : ( oldVnode , vnode ) => {
// invoked whenever a new virtual node is created
} ,
update : ( oldVnode , vnode ) => {
// invoked whenever a virtual node is updated
}
} ;Mit diesem Mechanismus können Sie das Verhalten von Snabbdom leicht erweitern. Zur Demonstration schauen Sie sich die Implementierungen der Standardmodule an.
Dies beschreibt die Kernmodule. Alle Module sind optional. JSX -Beispiele gehen davon aus, dass Sie die von dieser Bibliothek bereitgestellte jsx Pragma verwenden.
Das Klassenmodul bietet eine einfache Möglichkeit, Klassen auf Elementen dynamisch umzuschalten. Es erwartet ein Objekt in der class . Das Objekt sollte Unterrichtsnamen an Booleans abbilden, die angeben, ob die Klasse bleiben oder nicht auf dem VNODE gehen soll.
h ( "a" , { class : { active : true , selected : false } } , "Toggle" ) ; In JSX können Sie eine solche class verwenden:
< div class = { { foo : true , bar : true } } />
// Renders as: <div class="foo bar"></div>Ermöglicht Ihnen, Eigenschaften für DOM -Elemente festzulegen.
h ( "a" , { props : { href : "/foo" } } , "Go to Foo" ) ; In JSX können Sie solche props verwenden:
< input props = { { name : "foo" } } />
// Renders as: <input name="foo" /> with input.name === "foo"Eigenschaften können nur festgelegt werden. Nicht entfernt. Auch wenn Browser die Ergänzung und Löschung benutzerdefinierter Eigenschaften ermöglichen, wird dieses Modul nicht versucht. Dies ist sinnvoll, da native DOM -Eigenschaften nicht entfernt werden können. Und wenn Sie benutzerdefinierte Eigenschaften zum Speichern von Werten oder zur Referenzierung von Objekten auf der DOM verwenden, sollten Sie stattdessen Datenattribute verwenden. Vielleicht über das Datensatzmodul.
Gleich wie Requisiten, aber die Attribute anstelle von Eigenschaften für DOM -Elemente festlegen.
h ( "a" , { attrs : { href : "/foo" } } , "Go to Foo" ) ; In JSX können Sie attrs wie folgt verwenden:
< div attrs = { { "aria-label" : "I'm a div" } } />
// Renders as: <div aria-label="I'm a div"></div> Attribute werden mit setAttribute hinzugefügt und aktualisiert. Bei einem zuvor hinzugefügten/festgelegten Attribut und im attrs -Objekt wird es mit removeAttribute aus der Attributliste des DOM -Elements nicht mehr vorhanden.
Bei booleschen Attributen (z. B. disabled , hidden , selected ...) hängt die Bedeutung nicht vom Attributwert ( true oder false ) ab, hängt jedoch von der Anwesenheit/Abwesenheit des Attributs selbst im DOM -Element ab. Diese Attribute werden vom Modul unterschiedlich behandelt: Wenn ein boolescher Attribut auf einen falsy -Wert ( 0 , -0 , null , false , NaN , undefined oder die leere Zeichenfolge ( "" ) festgelegt wird, wird das Attribut aus der Attributliste des DOM -Elements entfernt.
Ermöglicht Ihnen, benutzerdefinierte Datenattribute ( data-* ) für DOM-Elemente festzulegen. Diese können dann mit der Eigenschaft htmlelement.dataset zugegriffen werden.
h ( "button" , { dataset : { action : "reset" } } , "Reset" ) ; In JSX können Sie einen solchen dataset verwenden:
< div dataset = { { foo : "bar" } } />
// Renders as: <div data-foo="bar"></div>Das Stilmodul dient dazu, dass Ihr HTML glatt aussieht und reibungslos animiert. Im Kern können Sie CSS -Eigenschaften auf Elementen einstellen.
h (
"span" ,
{
style : {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
}
} ,
"Say my name, and every colour illuminates"
) ; In JSX können Sie einen solchen style verwenden:
< div
style = { {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
} }
/>
// Renders as: <div style="border: 1px solid #bada55; color: #c0ffee; font-weight: bold"></div> CSS -benutzerdefinierte Eigenschaften (auch bekannt als CSS -Variablen) werden unterstützt, sie müssen vorangestellt werden --
h (
"div" ,
{
style : { "--warnColor" : "yellow" }
} ,
"Warning"
) ; Sie können Eigenschaften als verzögert angeben. Wenn sich diese Eigenschaften ändern, wird die Änderung erst nach dem nächsten Frame angewendet.
h (
"span" ,
{
style : {
opacity : "0" ,
transition : "opacity 1s" ,
delayed : { opacity : "1" }
}
} ,
"Imma fade right in!"
) ;Dies erleichtert es einfach, den Eintritt von Elementen deklarativ zu animieren.
Der all Wert der transition-property wird nicht unterstützt.
remove Die in der Eigenschaft remove eingestellten Stile werden wirksam, sobald das Element aus dem DOM entfernt wird. Die angewandten Stile sollten mit CSS -Übergängen animiert werden. Nur wenn alle Stile abgeschlossen sind, wird das Element aus dem DOM entfernt.
h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
remove : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ;Dies erleichtert es leicht, die Entfernung von Elementen deklarativ zu animieren.
Der all Wert der transition-property wird nicht unterstützt.
destroy festlegen h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
destroy : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ; Der all Wert der transition-property wird nicht unterstützt.
Das Event -Hörer -Modul bietet leistungsstarke Funktionen zum Anbringen von Event -Hörern.
Sie können einer Veranstaltung auf einem VNODE eine Funktion anhängen, indem Sie ein Objekt mit einer Eigenschaft on , die dem Namen des Ereignisses entspricht, das Sie anhören möchten. Die Funktion wird aufgerufen, wenn das Ereignis stattfindet, und wird an das Ereignisobjekt übergeben, das dazu gehört.
function clickHandler ( ev ) {
console . log ( "got clicked" ) ;
}
h ( "div" , { on : { click : clickHandler } } ) ; In JSX können Sie on folgt verwenden:
< div on = { { click : clickHandler } } />Snabbdom ermöglicht den Austausch von Ereignishandlern zwischen Rendern. Dies geschieht, ohne die Event -Handler, die dem DOM angeschlossen sind, tatsächlich zu berühren.
Beachten Sie jedoch, dass Sie bei der Freigabe von Ereignishandlern zwischen VNODES vorsichtig sein sollten , da dieses Modul dieses Modul verwendet, um die Wiederaufbindung von Ereignishandlern an das DOM zu vermeiden. (Und im Allgemeinen funktioniert das Teilen von Daten zwischen VNODES nicht garantiert, da Module die angegebenen Daten mutieren dürfen).
Insbesondere sollten Sie so etwas nicht tun:
// 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
} )
] ) ; In vielen solchen Fällen können Sie stattdessen Array-basierte Handler verwenden (oben beschrieben). Stellen Sie alternativ einfach sicher, dass jeder Knoten on Werte eindeutig übergeben wird:
// 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 funktioniert nur, wenn die h -Funktion zum Erstellen von virtuellen Knoten verwendet wird. SVG -Elemente werden automatisch mit den entsprechenden Namespaces erstellt.
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"
}
} )
] )
] ) ;Siehe auch das SVG -Beispiel und das SVG -Karussell -Beispiel.
Bestimmte Browser (wie dh <= 11) unterstützen classList -Eigenschaft in SVG -Elementen nicht. Da das Klassenmodul intern classList verwendet, funktioniert es in diesem Fall nicht, es sei denn, Sie verwenden eine Klassenlist -Polyfill. (Wenn Sie keine Polyfill verwenden möchten, können Sie das class mit dem Attribute -Modul verwenden.)
Die thunk -Funktion nimmt einen Selektor, einen Schlüssel zur Identifizierung eines Thunk, eine Funktion, die einen VNODE und eine variable Menge an Statusparametern zurückgibt. Wenn er aufgerufen wird, erhält die Renderfunktion die staatlichen Argumente.
thunk(selector, key, renderFn, [stateArguments])
Das renderFn wird nur aufgerufen [stateArguments] wenn das renderFn geändert wird oder die Arraylänge der Array oder ihre Elemente geändert werden.
Der key ist optional. Es sollte geliefert werden, wenn der selector unter den Thunks -Geschwistern nicht einzigartig ist. Dies stellt sicher, dass der Thunk beim Differenz immer korrekt angepasst wird.
Thunks sind eine Optimierungsstrategie, die angewendet werden kann, wenn man mit unveränderlichen Daten zu tun hat.
Betrachten Sie eine einfache Funktion zum Erstellen eines virtuellen Knotens basierend auf einer Zahl.
function numberView ( n ) {
return h ( "div" , "Number is: " + n ) ;
} Die Ansicht hängt nur von n ab. Dies bedeutet, dass es verschwenderisch ist, wenn n unverändert ist, den virtuellen DOM -Knoten zu erstellen und gegen den alten VNode zu pflücken. Um den Overhead zu vermeiden, können wir die Funktion thunk -Helfer verwenden.
function render ( state ) {
return thunk ( "num" , numberView , [ state . number ] ) ;
} Anstatt die numberView -Funktion tatsächlich aufzurufen, wird nur eine Dummy -Vnode in den virtuellen Baum gelegt. Wenn Snabbdom diesen Dummy -Vnode gegen einen vorherigen VNODE patches, wird der Wert von n vergleicht. Wenn n unverändert ist, wird der alte VNode einfach wiederverwendet. Dadurch wird vermieden, dass die Zahlenansicht und der Diff -Prozess insgesamt nachgebildet werden.
Die Ansichtsfunktion hier ist nur ein Beispiel. In der Praxis sind die Thunks nur dann relevant, wenn Sie eine komplizierte Ansicht machen, deren Generierung erhebliche Rechenzeit benötigt.
Beachten Sie, dass JSX -Fragmente immer noch experimentell sind und angepasst werden müssen. Einzelheiten finden Sie in fragment .
Fügen Sie Ihrem tsconfig.json die folgenden Optionen hinzu:
{
"compilerOptions" : {
"jsx" : " react " ,
"jsxFactory" : " jsx " ,
"jsxFragmentFactory" : " Fragment "
}
} Stellen Sie dann sicher, dass Sie die .tsx -Dateierweiterung verwenden und die jsx -Funktion und die Fragment oben in der Datei importieren:
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
</ >
) ;Fügen Sie Ihrer Babel -Konfiguration die folgenden Optionen hinzu:
{
"plugins" : [
[
" @babel/plugin-transform-react-jsx " ,
{
"pragma" : " jsx " ,
"pragmaFrag" : " Fragment "
}
]
]
} Importieren Sie dann die jsx -Funktion und die Fragment oben in der Datei:
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
</ >
) ; Eigenschaften
Die sel -Eigenschaft gibt das HTML -Element des VNODE an, optional seine id , die von einem # und null oder mehr Klassen vorangestellt ist, die jeweils durch a vorangestellt sind . . Die Syntax ist von CSS -Selektoren inspiriert. Hier sind einige Beispiele:
div#container.bar.baz - Ein div -Element mit dem ID container und der bar und baz .li - ein li -Element ohne id noch Klassen.button.alert.primary - button mit den beiden Klassen alert und primary . Der Selektor soll statisch sein, das heißt, er sollte sich während der Lebensdauer des Elements nicht ändern. Um eine dynamische id festzulegen, verwenden Sie das Props -Modul und um dynamische Klassen einzustellen. Verwenden Sie das Klassenmodul.
Da der Selektor statisch ist, verwendet Snabbdom ihn als Teil einer Vnodes -Identität. Zum Beispiel, wenn die beiden Kinder vnodes
[ h ( "div#container.padding" , children1 ) , h ( "div.padding" , children2 ) ] ;sind geflickt
[ h ( "div#container.padding" , children2 ) , h ( "div.padding" , children1 ) ] ;Anschließend verwendet Snabbdom den Selektor, um die VNodes zu identifizieren und sie im DOM -Baum neu zu ordnen, anstatt ein neues DOM -Element zu erstellen. Diese Verwendung von Selektoren vermeidet die Notwendigkeit, in vielen Fällen Schlüssel anzugeben.
Die .data -Eigenschaft eines virtuellen Knotens ist der Ort, an dem Informationen für Module hinzugefügt werden können, um auf das reale DOM -Element beim Erstellen zuzugreifen und zu manipulieren. Fügen Sie Stile, CSS -Klassen, Attribute usw. hinzu.
Das Datenobjekt ist der (optionale) zweite Parameter zu h()
Zum Beispiel h('div', {props: {className: 'container'}}, [...]) erzeugt einen virtuellen Knoten mit
( {
props : {
className : "container"
}
} ) ; als sein .data -Objekt.
Die .children eines virtuellen Knotens ist der dritte (optionale) Parameter zu h() während der Erstellung. .children ist einfach eine Reihe virtueller Knoten, die bei der Erstellung als Kinder des übergeordneten Domknotens hinzugefügt werden sollten.
Zum Beispiel h('div', {}, [ h('h1', {}, 'Hello, World') ]) wird einen virtuellen Knoten mit erstellen
[
{
sel : "h1" ,
data : { } ,
children : undefined ,
text : "Hello, World" ,
elm : Element ,
key : undefined
}
] ; als sein. .children .
Die .text -Eigenschaft wird erstellt, wenn ein virtueller Knoten mit nur einem einzelnen Kind erstellt wird, das Text besitzt und nur document.createTextNode() benötigt.
Zum Beispiel: h('h1', {}, 'Hello') erstellt einen virtuellen Knoten mit Hello als .text -Eigenschaft.
Die Eigenschaft eines virtuellen Knotens .elm Diese Eigenschaft ist sehr nützlich, um Berechnungen in Haken und Modulen durchzuführen.
Die Eigenschaft .key wird erstellt, wenn in Ihrem .data -Objekt ein Schlüssel zur Verfügung gestellt wird. Die Eigenschaft .key Dies ist sehr nützlich für Dinge wie das Nachbestehen von Listen. Ein Schlüssel muss entweder eine Zeichenfolge oder eine Zahl sein, um eine ordnungsgemäße Suche zu ermöglichen, da es intern als Schlüssel-/Wertpaar in einem Objekt gespeichert wird, wobei .key der Schlüssel ist und der Wert die .elm -Eigenschaft erstellt ist.
Wenn die .key -Immobilie bei den Geschwisterelementen einzigartig sein.
Zum Beispiel: h('div', {key: 1}, []) erstellt ein virtuelles Knotenobjekt mit einer .key -Eigenschaft mit dem Wert von 1 .
Snabbdom ist eine virtuelle DOM-Bibliothek auf niedriger Ebene. Es ist in Bezug auf die Art und Weise, wie Sie Ihre Bewerbung strukturieren sollten, nicht ab.
Hier sind einige Ansätze zum Aufbau von Anwendungen mit Snabbdom.
Stellen Sie sicher, dass Sie es teilen, wenn Sie eine Anwendung auf eine andere Weise mit Snabbdom erstellen.
Pakete im Zusammenhang mit Snabbdom sollten mit dem Schlüsselwort snabbdom markiert und auf NPM veröffentlicht werden. Sie können mit den 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.
Der Grund für diesen Fehler ist die Wiederverwendung von VNODes zwischen Patches (siehe Code -Beispiel).
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 ) ;Sie können dieses Problem beheben, indem Sie eine flache Kopie des Objekts erstellen (hier mit Objektverbreitungssyntax):
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ { ... sharedNode } ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;Eine andere Lösung wäre, gemeinsame Vnodes in einer Fabrikfunktion einzuwickeln:
const sharedNode = ( ) => h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ( ) ] )
] ) ; Zugangsanfragen, die die Community möglicherweise für Feedback geben kann, sollte nach einer solchen Gelegenheit von einigen Tagen verschmolzen werden.