Dies ist der zweite, letzte Teil des Tutorials, in dem wir den TodoMVC-Client unter Verwendung des minimalistischen reaktiven
ds js-Frameworks schreiben.
Zusammenfassung des
ersten Teils : Wir haben vom Server eine Aufgabenliste im JSON-Format erhalten, daraus eine HTML-Liste erstellt, die Möglichkeit hinzugefĂŒgt, den Namen und das Abschlusszeichen fĂŒr jeden Fall zu bearbeiten, und eine Serverbenachrichtigung ĂŒber diese Ănderungen implementiert.
Es bleibt abzuwarten: Löschen beliebiger FĂ€lle, HinzufĂŒgen neuer FĂ€lle, Masseninstallation / ZurĂŒcksetzen und Filtern von FĂ€llen nach Fertigstellung und die Funktion zum Löschen aller abgeschlossenen FĂ€lle. Das werden wir tun. Die endgĂŒltige Version des Clients, auf die wir in diesem Artikel eingehen, finden Sie
hier .
Die Option, die wir letztes Mal gewÀhlt haben, kann hier aufgefrischt
werden .
Hier ist sein Code:
'#todoapp'.d("" ,'#header'.d("" ,'H1'.d("") ,'INPUT#new-todo placeholder="What needs to be done?" autofocus'.d("") ) ,'#main'.d("" ,'#toggle-all type=checkbox'.d("") ,'UL#todo-list'.d("*@ todos:query" ,'LI'.d("$completed=.completed $editing= $patch=; a!" ,'INPUT.toggle type=checkbox' .d("#.checked=.completed") .ui("$patch=($completed=#.checked)") ,'LABEL.view' .d("? $editing:!; ! .title") .e("dblclick","$editing=`yes") ,'INPUT.edit' .d("? $editing; !! .title@value") .ui("$patch=(.title=#.value)") .e("blur","$editing=") ,'BUTTON.destroy'.d("") ) .a("!? $completed $editing") .u("? $patch; (@method`PATCH .url:dehttp headers $patch@):query $patch=") ) ) ,'#footer'.d("" ,'#todo-count'.d("") ,'UL#filters'.d("" ,'LI'.d("") ) ,'#clear-completed'.d("") ) ) .DICT({ todos : "//todo-backend-express.herokuapp.com/", headers: {"Content-type":"application/json"} }) .FUNC({ convert:{ dehttp: url=>url.replace(/^https?\:/,'') } }) .RENDER()
Jetzt gibt es hier nur noch fĂŒnfzig Zeilen, aber am Ende des Artikels werden es doppelt so viele sein - bis zu 100. Es werden viele HTTP-Anfragen an den Server gesendet. Ăffnen Sie daher bitte die Entwicklertools (in Chrome, wie Sie sich erinnern, Strg + Umschalt + I) Erstens ist die Registerkarte Netzwerk interessant, und zweitens die Konsole. Vergessen Sie auch nicht, den Code fĂŒr jede Version unserer Seite anzuzeigen - in Chrome ist dies Strg + U.
Hier muss ich einen kleinen Exkurs machen. Wenn Sie den
ersten Teil des Tutorials nicht gelesen haben, wĂŒrde ich dennoch empfehlen, damit zu beginnen. Wenn Sie es gelesen haben, aber nichts verstanden haben, ist es besser, es erneut zu lesen. Wie die Kommentare zu meinen beiden vorherigen Artikeln zeigen, werden die Syntax und das Prinzip von dap von einem unvorbereiteten Leser nicht immer sofort verstanden. Ein anderer Artikel ist nicht zum Lesen fĂŒr Personen zu empfehlen, denen das Auftreten einer nicht si-Ă€hnlichen Syntax unangenehm ist.

Dieser zweite Teil des Tutorials ist etwas komplizierter und interessanter als der erste.
[TODO: Bitten Sie Token, einen SchĂŒler zu finden, der im Internet ein Gehirnbild explodiert] .
Mit Ihrer Erlaubnis werde ich die Kapitel mit Teil 1 weiter nummerieren. Dort haben wir bis 7 gezÀhlt. Also,
8. Erstellen einer Aufgabenliste fĂŒr die Statusvariable
Um einen Fall aus der Liste zu entfernen, gibt es eine SchaltflÀche
BUTTON.destroy
. Das Entfernen besteht darin, eine DELETE-Anforderung an den Server zu senden und das entsprechende
UL#todo-list > LI
Element
UL#todo-list > LI
mit dem gesamten Inhalt tatsÀchlich aus dem Blickfeld zu entfernen. Mit dem Senden einer DELETE-Anfrage ist alles klar:
,'BUTTON.destroy'.ui("(@method`DELETE .url:dehttp):query")
Mit dem Entfernen eines Elements vom Bildschirm sind jedoch Optionen möglich. Man könnte einfach eine andere Statusvariable einfĂŒhren, beispielsweise
$deleted
, und das Element mit CSS ausblenden, einschlieĂlich der
deleted
CSS-Klasse
,'LI'.d("$completed=.completed $editing= $patch= $deleted=; a!"
Und es wĂŒrde funktionieren. Aber es wĂ€re Betrug. DarĂŒber hinaus werden wir weiter unten Filter und ZĂ€hler fĂŒr aktive und abgeschlossene FĂ€lle haben (was in
#footer
). Daher ist es besser, das Objekt sofort âphysischâ von der To-Do-Liste zu entfernen. Das heiĂt, wir mĂŒssen das Array selbst Ă€ndern können, das wir ursprĂŒnglich vom Server erhalten haben. Das bedeutet, dass dieses Array auch eine Statusvariable werden muss. Nennen wir sie
$todos
.
Der Bereich der Variablen
$todos
besteht darin, den gemeinsamen Vorfahren aller Elemente auszuwÀhlen, die auf diese Variable zugreifen. Und es wird durch
INPUT#new-todo
von
#header
und ZĂ€hler von
#footer
und tatsÀchlich
UL#todo-list
#footer
. Der gemeinsame Vorfahr von allen ist das Wurzelelement der Vorlage,
#todoapp
. Daher definieren wir in seiner D-Regel die Variable
$todos
. An derselben Stelle laden wir die Daten sofort vom Server auf den Server hoch. Und um die Liste
UL#todo-list
zu erstellen, werden wir jetzt auch davon sein:
'#todoapp'.d("$todos=todos:query"
Es ist wichtig. Wenn beim Testen plötzlich die To-Do-Liste nicht geladen wird - ist es gut möglich, dass jemand sie alle gelöscht hat (dies ist ein öffentlicher Server, und dort kann alles passieren).
In diesem Fall gehen Sie bitte zu einem
vollstÀndigen Beispiel und erstellen Sie einige FÀlle, mit denen Sie experimentieren können.
Wir schauen Hier wird
$todos
in der d-Regel des
#todoapp
Elements
#todoapp
und sofort
mit den erforderlichen Daten
initialisiert . Alles scheint zu funktionieren, aber eine unangenehme Eigenschaft ist aufgetreten. Wenn der Server lÀngere Zeit auf die Anfrage reagiert (in Chrome können Sie diese Situation simulieren: Auf der Registerkarte "Netzwerk" der Entwicklertools können Sie verschiedene Modi zum Simulieren langsamer Netzwerke auswÀhlen), sieht unsere neue Version der Anwendung bis zur Fertigstellung der Anfrage ein wenig traurig aus - es gibt nur CSS Artefakte. Ein solches Bild wird den Benutzer definitiv nicht begeistern. Obwohl die VorgÀngerversion nicht darunter litt - bis die Daten auf der Seite eingingen, fehlte nur die Liste selbst, aber andere Elemente tauchten sofort auf, ohne auf die Daten zu warten.
Hier ist das Ding. Wie Sie sich erinnern, ist der
:query
asynchron. Diese AsynchronitĂ€t drĂŒckt sich darin aus, dass bis zum Abschluss der Anforderung nur die AusfĂŒhrung der aktuellen Regel blockiert ist, dh die Generierung des Elements, das die angeforderten Daten tatsĂ€chlich benötigt (was logisch ist). Die Erzeugung anderer Elemente wird nicht blockiert. Daher wurde beim Zugriff von
UL#todo-list
auf den Server nur dieser blockiert, nicht jedoch
#header
und
#footer
, die sofort gezeichnet wurden. Nun wartet die gesamte
#todoapp
auf die Fertigstellung der Anfrage.
9. Verzögertes Laden der Daten
Um die Situation zu korrigieren und nicht beteiligte Elemente nicht zu blockieren, verschieben wir das erstmalige Laden der Daten, bis alles bereits gezeichnet ist. Dazu laden wir die Daten nicht sofort in die Variable
$todos
, sondern initialisieren sie zunĂ€chst einfach mit ânichtsâ.
'#todoapp'.d("$todos="
Sie wird also nichts blockieren und die gesamte Vorlage wird funktionieren - allerdings vorerst mit einer leeren âTo-Do-Listeâ. Mit einem langweiligen Einstiegsbildschirm können Sie
$todos
jetzt sicher
Ă€ndern, indem Sie eine To-Do-Liste hochladen.
#todoapp
Sie dazu diesen Nachkommen zu
#todoapp
,'loader' .u("$todos=todos:query")
Dieses Element hat eine U-Regel, die genau so aussieht wie die Blockierungsregel, die wir abgelehnt haben, aber es gibt einen grundlegenden Unterschied.
Lassen Sie mich daran erinnern, dass die D-Regel (von
unten ) die Elementgenerierungsregel ist, die ausgefĂŒhrt wird, wenn die Vorlage von oben nach
unten erstellt wird , vom ĂŒbergeordneten Element bis zu den
untergeordneten Elementen. und U-Regeln (von
oben ) sind Reaktionsregeln, die als Reaktion auf ein Ereignis ausgefĂŒhrt werden, das von unten nach
oben und von Kind zu Eltern auftaucht.
Wenn also
einer Variablen
in der D-Regel etwas (einschlieĂlich ânichtsâ) zugewiesen ist, bedeutet dies, dass sie im GĂŒltigkeitsbereich dieses Elements
deklariert und initialisiert wird und ihre Nachkommen (verschachtelte GĂŒltigkeitsbereiche werden wie in JS in DAP implementiert) ) Zuweisung
in up-rules bedeutet eine
Ănderung einer Variablen, die zuvor im GĂŒltigkeitsbereich deklariert wurde. Die Deklaration und Initialisierung von Variablen in der d-Regel ermöglicht es dem ĂŒbergeordneten Element, die fĂŒr die Konstruktion erforderlichen Informationen an die untergeordneten Elemente in der Hierarchie weiterzugeben, und die Ănderung ermöglicht es dem ĂŒbergeordneten Element, Aktualisierungen an diese Informationen weiterzugeben und so eine angemessene Umstrukturierung aller davon abhĂ€ngigen Elemente einzuleiten.
Das
loader
Element, das ein Abkömmling von
#todoapp
,
#todoapp
in seiner U-Regel
die Variable
$todos
und lÀdt Daten vom Server hinein, wodurch alle Consumer-Elemente dieser Variablen (und nur diese, was wichtig ist!) Automatisch neu
#todoapp
. Verbraucher einer Variablen sind Elemente, deren D-Regeln diese Variable als einen Wert enthalten, d.h. Diejenigen,
die diese Variable (unter BerĂŒcksichtigung des GĂŒltigkeitsbereichs) beim Erstellen
lesen .
Wir haben jetzt einen Konsumenten der Variablen
$todos
- die eigentliche
UL#todo-list
, die dementsprechend nach dem Laden der Daten neu erstellt wird.
,'UL#todo-list'.d("*@ $todos"
Jetzt haben wir also eine
#todoapp
, die eine Statusvariable in
#todoapp
, ohne das anfÀngliche Rendern der Vorlage zu blockieren.
10. Löschen und HinzufĂŒgen von Aufgaben
Jetzt können wir
$todos
jeder Hinsicht Àndern. Beginnen wir mit dem Entfernen der Elemente. Wir haben bereits einen Button-Cross
BUTTON.destroy
, der die Server-Entfernungsanfragen bisher einfach sendet
,'BUTTON.destroy'.ui("(@method`DELETE .url:dehttp):query")
Es muss sichergestellt werden, dass das entsprechende Objekt auch aus der Variablen
$todos
gelöscht wird. Da dies eine Ănderung ist, wird
UL#todo-list
als Consumer dieser Variablen automatisch neu erstellt, jedoch ohne das gelöschte Element.
Dap bietet an sich keine speziellen Möglichkeiten zur Manipulation von Daten. Manipulationen können perfekt in Funktionen in JS geschrieben werden, und DAP-Regeln liefern ihnen einfach Daten und nehmen das Ergebnis auf. Wir schreiben eine JS-Funktion, um ein Objekt aus einem Array zu entfernen, ohne seine Nummer zu kennen. Zum Beispiel das:
const remove = (arr,tgt)=> arr.filter( obj => obj!=tgt );
Sie können wahrscheinlich etwas effektiveres schreiben, aber darum geht es jetzt nicht. Es ist unwahrscheinlich, dass unsere Anwendung mit Aufgabenlisten von Millionen von Elementen arbeiten muss. Wichtig ist, dass die Funktion ein neues Array-Objekt zurĂŒckgibt und nicht nur das Element von dem entfernt, was es ist.
Um diese Funktion ĂŒber DAP-Regeln zugĂ€nglich zu machen, mĂŒssen Sie sie dem Abschnitt
.FUNC
hinzufĂŒgen, aber vorher entscheiden, wie wir sie aufrufen möchten. In diesem Fall besteht die einfachste Möglichkeit darin, sie vom Konverter aufzurufen, der das Objekt
{ todos, tgt }
akzeptiert und ein gefiltertes Array zurĂŒckgibt
.FUNC({ convert:{ dehttp: url => url.replace(/^https?\:/,''),
Aber nichts
.FUNC
Sie daran, diese Funktion direkt in
.FUNC
(Ich habe bereits gesagt, dass
.FUNC
eine regulÀre JS-Methode ist und das Argument ein regulÀres JS-Objekt.)
.FUNC({ convert:{ dehttp: url => url.replace(/^https?\:/,''), remove: x => x.todos.filter( todo => todo!=x.tgt ) } })
Jetzt können wir ĂŒber die DAP-Regeln auf diesen Konverter zugreifen
,'BUTTON.destroy' .ui("$todos=($todos $@tgt):remove (@method`DELETE .url:dehttp):query")
Hier bilden wir zuerst ein Objekt, das in der JS-Notation mit
{ todos, tgt:$ }
, ĂŒbergeben es an den in
.FUNC
beschriebenen
:remove
Konverter und geben das gefilterte Ergebnis an
$todos
, wodurch es
.FUNC
wird. Hier ist
$
der
Datenkontext des Elements, des GeschÀftsobjekts aus dem Array
$todos
auf dem die Vorlage basiert. Nach dem
@
-Symbol wird der Alias ââdes Arguments angezeigt. Wenn
@
fehlt, wird der eigene Name des Arguments verwendet. Dies Ă€hnelt der kĂŒrzlichen
AbkĂŒrzung von ES6 Innovation -
Property .
In Ă€hnlicher Weise fĂŒgen wir der Liste einen neuen Fall hinzu, indem wir das Element
INPUT#new-todo
und die POST-Anforderung verwenden
,'INPUT#new-todo placeholder="What needs to be done?" autofocus' .ui("$=(#.value@title) (@method`POST todos@url headers $):query $todos=($todos $@tgt):insert #.value=") ... .FUNC({ convert:{ dehttp: url => url.replace(/^https?\:/,''), remove: x => x.todos.filter( todo => todo!=x.tgt ),
Die Reaktionsregel des
INPUT#new-todo
Elements auf ein Standard-UI-Ereignis (fĂŒr die
INPUT
Elemente wird das
change
Ereignis als Standard-DAP betrachtet) umfasst Folgendes: Lesen von Benutzereingaben aus der
value
Eigenschaft dieses Elements, Bilden eines lokalen
$
.title
mit diesem Wert als
.title
Feld, Senden von
$
.title
Ăndern Sie mit der POST-Methode das Array
$todos
indem Sie den Kontext
$
als neues Element hinzufĂŒgen und schlieĂlich die
value
Eigenschaft des
INPUT
Elements
INPUT
.
Hier könnte ein junger Leser fragen: Warum sollte
concat()
wenn ein Element zu einem Array hinzugefĂŒgt wird, wenn dies mit
concat()
push()
? Ein erfahrener Leser wird sofort verstehen, was los ist, und seine Antwort in die Kommentare schreiben.
Wir schauen uns an, was
passiert ist: FĂ€lle werden normal hinzugefĂŒgt und gelöscht, die entsprechenden Anfragen werden korrekt an den Server gesendet (Sie lassen die Registerkarte Netzwerk die ganze Zeit geöffnet, oder?). Aber was ist, wenn wir den Namen oder Status eines neu hinzugefĂŒgten Falls Ă€ndern möchten? Das Problem besteht darin, dass wir zum Benachrichtigen des Servers ĂŒber diese Ănderungen
.url
benötigen, mit der der Server diesem Unternehmen
.url
wird. Als wir das GeschÀft erstellt haben, kannten
.url
die
.url
bzw. wir können nicht die richtige PATCH-Ănderungsanforderung erstellen.
TatsÀchlich sind alle erforderlichen Informationen zu dem Fall in der Antwort des Servers auf die POST-Anforderung enthalten. Es wÀre richtiger, ein neues GeschÀftsobjekt nicht nur aus Benutzereingaben, sondern auch aus der Antwort des Servers zu erstellen und dieses Objekt mit allen bereitgestellten Informationen zu
$todos
hinzuzufĂŒgen Serverinformationen, einschlieĂlich des
.url
,'INPUT#new-todo placeholder="What needs to be done?" autofocus' .ui("$todos=($todos (@method`POST todos@url headers (#.value@title)):query@tgt ):insert #.value=")
Wir sehen aus - okay, jetzt wird alles richtig ausgearbeitet. Benachrichtigungen an den Server ĂŒber die Bearbeitung von neu erstellten FĂ€llen sind in Ordnung.
Man könnte damit aufhören, aber ... Wenn Sie genau hinschauen, können Sie immer noch eine leichte Verzögerung zwischen der Eingabe des Namens des neuen Falls und dem Moment feststellen, in dem er in der Liste erscheint. Diese Verzögerung ist deutlich sichtbar, wenn Sie ein simuliertes langsames Netzwerk einschalten. Wie Sie vielleicht erraten haben, handelt es sich um eine Anfrage an den Server: Zuerst fordern wir Daten fĂŒr einen neuen Fall vom Server an, und erst nach Erhalt Ă€ndern wir
$todos
. Im nÀchsten Schritt werden wir versuchen, diese Situation zu korrigieren, aber zuerst werde ich Ihre Aufmerksamkeit auf einen anderen interessanten Punkt lenken. Wenn wir ein wenig zur
vorherigen Version zurĂŒckkehren , stellen wir fest: Obwohl die Anforderung auch vorhanden ist, wird die neue GroĂ- / Kleinschreibung sofort zur Liste hinzugefĂŒgt, ohne auf das Ende der Anforderung zu warten
Dies ist ein weiteres Merkmal beim Ausarbeiten von Asynchronkonvertern in dap: Wenn das Ergebnis des Asynchronkonverters nicht verwendet wird (d. H., Es ist keiner Zuordnung zugeordnet), können Sie nicht auf seinen Abschluss warten - und die AusfĂŒhrung der Regel wird nicht blockiert. Dies ist hĂ€ufig hilfreich: Sie haben möglicherweise bemerkt, dass beim Löschen von FĂ€llen aus der Liste diese sofort vom Bildschirm verschwinden, ohne auf das Ergebnis der DELETE-Anforderung zu warten. Dies macht sich insbesondere dann bemerkbar, wenn Sie schnell mehrere FĂ€lle hintereinander löschen und Anforderungen im Netzwerkfenster nachverfolgen.
Da wir jedoch das Ergebnis der POST-Anforderung verwenden - es dem
$
-Kontext zuweisen - mĂŒssen wir warten, bis der Vorgang abgeschlossen ist. Daher mĂŒssen Sie einen anderen Weg finden, um
$todos
zu Ă€ndern, bevor Sie die POST-Anforderung ausfĂŒhren. Lösung: Erstellen Sie dennoch zuerst ein neues GeschĂ€ftsobjekt und fĂŒgen Sie es sofort zu
$todos
, lassen Sie die Liste zeichnen, und fĂŒhren Sie erst dann nach dem Rendern eine POST-Anforderung aus, wenn das GeschĂ€ft
.url
(
.url
das GeschÀft wurde gerade erstellt) Das Ergebnis wird dem Datenkontext dieses Falls auferlegt.
Als erstes fĂŒgen wir der
.title
ein Leerzeichen hinzu, das nur
.title
enthÀlt
,'INPUT#new-todo placeholder="What needs to be done?" autofocus' .ui("$todos=($todos (#.value@title)@tgt):insert #.value=")
UL#todo-list > LI
Regel zur Erzeugung von
UL#todo-list > LI
Elementen enthÀlt bereits
a!
Starten einer A-Regel nach dem erstmaligen Zeichnen des Elements. Dort können wir den Start einer POST-Anfrage in Abwesenheit von
.url
. Um zusĂ€tzliche Felder in den Kontext einzufĂŒgen, hat dap den Operator
&
.a("!? $completed $editing; ? .url:!; & (@method`POST todos@url headers $):query")
Wir schauen Eine andere Sache! Selbst in einem langsamen Netzwerk wird die Aufgabenliste sofort aktualisiert und die Serverbenachrichtigung und das Laden fehlender Daten erfolgt nach dem Zeichnen der aktualisierten Liste im Hintergrund.
11. Daw jeder!
Im Element
#header
befindet sich fĂŒr alle FĂ€lle in der Liste eine SchaltflĂ€che zum Masseninstallieren / ZurĂŒcksetzen des Abschlusszeichens. FĂŒr die Massenzuweisung von Werten zu den Feldern der Elemente des Arrays schreiben wir einfach einen anderen Konverter
:assign
und auf
$todos
anwenden, indem Sie auf
INPUT#toggle-all
klicken
,'INPUT#toggle-all type=checkbox' .ui("$todos=($todos (#.checked@completed)@src):assign") ... assign: x => x.todos && x.todos.map(todo => Object.assign(todo,x.src))
In diesem Fall interessiert uns nur das Feld
.completed
, aber es ist leicht zu erkennen, dass Sie mit einem solchen Konverter die Werte aller Felder der Array-Elemente massiv Àndern können.
Ok, im
$todos
Array sind die
$todos
umgeschaltet, jetzt mĂŒssen wir den Server ĂŒber die vorgenommenen Ănderungen informieren. Im ursprĂŒnglichen Beispiel erfolgt dies durch Senden von PATCH-Anfragen fĂŒr jeden Fall - keine sehr effektive Strategie, aber es hĂ€ngt nicht mehr von uns ab. Ok, fĂŒr jeden Fall senden wir eine PATCH-Anfrage
.ui("*@ $todos=($todos (#.checked@completed)@src):assign; (@method`PATCH .url:dehttp headers (.completed)):query")
Wir schauen : Ein Klick auf eine gemeinsame Daw richtet alle einzelnen Daws aus und der Server wird durch entsprechende PATCH-Anfragen benachrichtigt. Norm
12. FĂ€lle nach Fertigstellung filtern
Neben der eigentlichen Aufgabenliste sollte die Anwendung auch in der Lage sein, FĂ€lle nach dem Abschlusszeichen zu filtern und ZĂ€hler fĂŒr abgeschlossene und nicht abgeschlossene Aufgaben anzuzeigen. NatĂŒrlich ist es fĂŒr das Filtern trivial, dieselbe
filter()
-Methode zu verwenden, die von JS selbst bereitgestellt wird.
Aber zuerst mĂŒssen Sie sicherstellen, dass das Feld "
.completed
fĂŒr jeden Fall immer "true" ist, und wenn Sie auf die einzelne Tagesordnung des Falls klicken, wird diese zusammen mit der Variablen "
$completed
aktualisiert. Bisher war uns das nicht wichtig, aber jetzt wird es so sein.
,'INPUT.toggle type=checkbox' .d("#.checked=.completed") .ui("$patch=(.completed=$completed=#.checked) $recount=()")
Der wichtige Punkt hierbei ist, dass der Datenkontext jedes Falls das Case-Objekt selbst ist, das im Array
$todos
. Keine einzige Kopie oder verwandte Konstruktion, sondern das Objekt selbst. Und alle Aufrufe der Felder
.title
,
.completed
url
- sowohl Lese- als auch Schreibzugriff - gilt direkt fĂŒr dieses Objekt. Damit die Filterung des
$todos
Arrays ordnungsgemÀà funktioniert, muss die VervollstÀndigung des Falls nicht nur in der MorgendÀmmerung auf dem Bildschirm, sondern auch im
.completed
Feld des
.completed
Objekts
.completed
werden.
Um nur FÀlle mit dem erforderlichen VollstÀndigkeitszeichen in der Liste
.completed
, filtern wir
$todos
einfach nach dem ausgewÀhlten Filter. Der ausgewÀhlte Filter ist, Sie haben es erraten, eine weitere Zustandsvariable unserer Anwendung, und wir werden ihn
$filter
. Um
$todos
nach dem ausgewÀhlten
$filter
gehen wir die Miniaturansicht entlang und fĂŒgen einfach einen weiteren Konverter der Form
{list, filter} => der gefilterten Liste hinzu , und wir werden die Namen und Filterfunktionen aus dem "assoziativen Array" (d. H. Gewöhnlichen JS) ĂŒbernehmen object)
todoFilters
const todoFilters={ "All": null, "Active": todo => !todo.completed, "Completed": todo => !!todo.completed }; '#todoapp'.d("$todos= $filter="
Wir prĂŒfen . Filter funktionieren einwandfrei. Eine Nuance besteht darin, dass die Namen der Filter zusammen angezeigt werden, weil Hier haben wir uns ein wenig von der DOM-Struktur des Originals entfernt und sind aus CSS herausgekommen. Aber wir werden spĂ€ter darauf zurĂŒckkommen.
13. ZĂ€hler abgeschlossener und aktiver FĂ€lle.
Um die ZĂ€hler abgeschlossener und aktiver FĂ€lle anzuzeigen, filtern Sie einfach
$todos
mit den entsprechenden Filtern und zeigen die LĂ€ngen der resultierenden Arrays an
,'#footer'.d("$active=($todos @filter`Active):filter $completed=($todos @filter`Completed):filter" ,'#todo-count'.d("! (active $active.length)format")
In
diesem Formular zeigen die Leistungsindikatoren beim Booten die korrekten Werte an, reagieren jedoch nicht auf spĂ€tere Ănderungen beim Abschluss von VorgĂ€ngen (wenn Sie auf die Tagesordnung klicken). Tatsache ist, dass Klicks auf Dohlen, die den Status jedes einzelnen Falls Ă€ndern, den Status von
$todos
nicht Ă€ndern - eine Ănderung eines Array-Elements ist keine Ănderung des Arrays. Daher benötigen wir ein zusĂ€tzliches Signal fĂŒr die Notwendigkeit, FĂ€lle neu zu registrieren. Ein solches Signal kann eine zusĂ€tzliche Zustandsvariable sein, die jedes Mal geĂ€ndert wird, wenn ein erneutes ZĂ€hlen erforderlich ist. Nennen wir es
$recount
. d- , ,
#footer
â d-
'#todoapp'.d("$todos= $filter= $recount="
, .
14. .
TodoMVC , â . , , , DELETE- â
$completed
. ,
$todos
,
$active
,'#clear-completed' .d("! (completed $completed.length)format") .ui("$todos=$active; *@ $completed; (@method`DELETE .url:dehttp):query")
: , . Network .
15.
. #. #- â . URL .
location.hash
urlhash
, , a-
#todoapp
( ),
$filter
.a("urlhash $filter")
$filter
hashchange -
:urlhash
,
location.hash
( #)
.d("$todos= $filter=:urlhash $recount=" .e("hashchange","$filter=:urlhash")
hashchange #- . , -
window
document.body
.
#todoapp
, d-
listen
,
window
'#todoapp' .a("urlhash $filter") .e("hashchange","$filter=:urlhash") .d("$todos= $filter=:urlhash $recount=; listen @hashchange"
: , ,
#Active ,
#All ,
#Completed . Alles arbeitet. . , , â . , â
,'UL#filters'.d("* filter" ,'LI'.d("" ,'A'.d("!! (`# .filter)concat@href .filter@") ) )
,
!?
, CSS-
selected
,
.filter
$filter
,'A'.d("!! (`# .filter)concat@href .filter@; !? (.filter $filter)eq@selected")
dap- ( ) ,
.
16.
, ,
head
HTML-
[ui=click]{cursor:pointer}
, .
, ! «todos». , , - , «todos» «dap todos»
,'H1'.d("","dap todos")
.
, ( ).
AbschlieĂend
, , dap- â «, », « , » .. . . , , , .
, , .