Ractive.js - Web-Apps leicht gemacht

Veröffentlicht: 2022-03-11

In der heutigen schnell wachsenden Landschaft von JavaScript-Frameworks und -Bibliotheken kann die Auswahl desjenigen, auf dem Sie Ihre Entwicklung aufbauen möchten, eine ziemliche Herausforderung sein. Schließlich ist die Migration Ihres Codes auf die Verwendung eines anderen Frameworks eine nicht triviale Aufgabe, für die Sie möglicherweise nie die Zeit oder das Budget haben, um sie auszuführen, sobald Sie den Weg eingeschlagen haben, ein bestimmtes Framework zu verwenden.

Warum also Ractive.js?

Im Gegensatz zu anderen Tools, die inertes HTML generieren, wandelt Ractive Vorlagen in Blaupausen für Apps um, die standardmäßig interaktiv sind. Und obwohl man sicherlich argumentieren könnte, dass der Beitrag von Ractive eher evolutionär als revolutionär ist, ist sein Wert dennoch signifikant.

Was Ractive so nützlich macht, ist, dass es leistungsstarke Funktionen bietet, dies jedoch auf eine Weise, die für den Entwickler erfrischend einfach zu bedienen ist. Außerdem ist es ziemlich elegant, schnell, unauffällig und klein.

In diesem Artikel gehen wir durch den Prozess der Erstellung einer einfachen Ractive-Such-App, demonstrieren einige der wichtigsten Funktionen von Ractive und zeigen, wie es hilft, Web-Apps und die Entwicklung zu vereinfachen.

Ractive.js und Web-Apps

Was ist Ractive.js?

Ractive wurde ursprünglich entwickelt, um das Datenbindungsproblem eleganter anzugehen. Zu diesem Zweck nimmt es Vorlagen und wandelt sie in eine leichtgewichtige virtuelle Darstellung des DOM um, sodass das echte DOM intelligent und effizient aktualisiert wird, wenn sich die Daten ändern.

Aber es zeigte sich bald, dass der Ansatz und die Infrastruktur von Ractive auch dazu genutzt werden könnten, andere Dinge effizienter zu erledigen. Es kann sich beispielsweise automatisch um Dinge wie die Wiederverwendung von Event-Handlern kümmern und sie automatisch entbinden, wenn sie nicht mehr benötigt werden. Ereignisdelegierung wird unnötig. Wie bei der Datenbindung verhindert dieser Ansatz, dass der Code unhandlich wird, wenn eine App wächst.

Schlüsselfunktionen wie bidirektionale Bindung, Animationen und SVG-Unterstützung werden sofort bereitgestellt, und benutzerdefinierte Funktionen können einfach über Plugins hinzugefügt werden.

Während einige Tools und Frameworks Sie dazu zwingen, ein neues Vokabular zu lernen und Ihre App auf eine bestimmte Weise zu strukturieren, arbeitet Ractive für Sie, nicht umgekehrt. Es lässt sich auch gut mit anderen Bibliotheken integrieren.

Unsere Beispiel-App

Unsere Beispiel-App wird verwendet, um die Toptal-Datenbank von Entwicklern basierend auf Fähigkeiten zu durchsuchen. Unsere App wird zwei Ansichten haben:

  • Suche: Fähigkeitenliste mit Inline-Suchfeld
  • Ergebnisse: Skill-Ansicht inklusive Liste der Entwickler

Für jeden Entwickler zeigen wir seinen Namen, sein Foto, eine kurze Beschreibung und eine Liste der Fertigkeiten an (jede Fertigkeit wird mit der entsprechenden Fertigkeitsansicht verknüpft).

(Hinweis: Am Ende dieses Artikels finden Sie Links zu einer funktionierenden Online-Instanz der Anwendung und zum Quellcode-Repository.)

Um unseren Hauptfokus auf dem Ractive-Framework zu behalten, werden wir eine Reihe von Vereinfachungen anwenden, die normalerweise in der Produktion nicht durchgeführt werden sollten:

  • Standardthema. Wir werden Bootstrap mit dem Standarddesign für das Styling verwenden, anstatt das Design an Ihren App-Stil anzupassen.
  • Abhängigkeiten. Wir werden unsere Abhängigkeiten als separate Skripts hinzufügen, die globale Variablen definieren (anstatt ES6-Module oder CommonJS oder AMD mit dem richtigen Ladeprogramm für die Entwicklung und den Build-Schritt für die Produktion zu verwenden).
  • Statische Daten. Wir werden statische Daten verwenden, die ich vorbereitet habe, indem ich die öffentlichen Seiten auf der Toptal-Website gekratzt habe.
  • Kein clientseitiges Routing. Das bedeutet, dass die URL gleich bleibt, wenn wir zwischen Ansichten wechseln. Für SPAs sollten Sie das definitiv nicht tun, obwohl es für einige kleine interaktive Komponenten in Ordnung sein kann. Ractive hat keine integrierte Router-Implementierung, kann aber mit Routern von Drittanbietern verwendet werden, wie in diesem Beispiel gezeigt.
  • Vorlagen, die in Skript-Tags in HTML definiert sind. Dies ist nicht unbedingt eine schlechte Idee, insbesondere für kleine Anwendungen, und es hat einige Vorteile (es ist einfach, und Sie können diese clientseitigen Vorlagen zusammen mit Ihren serverseitigen Vorlagen verarbeiten, beispielsweise zur Internationalisierung). Aber für größere Apps könnten Sie von der Vorkompilierung profitieren (auch bekannt als Pre-Parsing-Vorlagen für die interne JS-Darstellung).

Beginnen wir mit Web-Apps

OK, also lassen Sie uns mit dem Erstellen der App beginnen. Wir werden dies iterativ tun, indem wir nach und nach kleinere Funktionen hinzufügen und die Konzepte untersuchen, wenn wir ihnen begegnen.

Beginnen wir damit, einen Ordner mit zwei Dateien darin zu erstellen: index.html und script.js . Unsere App wird extrem einfach sein und mit dem file:// Protokoll arbeiten, um zu vermeiden, dass der Entwicklungsserver gestartet werden muss (obwohl Sie dies tun können, wenn Sie dies wünschen).

Die Suchseite

Wir beginnen mit der Implementierung der Suchseite, auf der der Benutzer eine Fähigkeit auswählen kann, für die er passende Entwickler in der Toptal-Datenbank findet.

HTML-Skelett

Beginnen wir mit dieser trivialen HTML-Seite:

 <html> <head> <title>Toptal Search</title> <!-- LOAD BOOTSTRAP FROM THE CDN --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> </head> <body> <!-- SOME BASIC STATIC CONTENT --> <div class="container"> <h1>Toptal Search</h1> </div> <!-- LOAD THE JAVASCRIPT LIBRARIES WE NEED --> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.9.3/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/0.7.3/ractive.min.js"></script> <!-- LOAD THE DATA --> <script src="https://rawgit.com/emirotin/toptal-blog-ractive/master/data.js"></script> <!-- LOAD OUR SCRIPT --> <script src="script.js"></script> </body> </html>

Wie Sie sehen können, handelt es sich um ein triviales HTML5-Dokument. Es lädt Bootstrap vom CDN, Lodash (eine großartige Datenmanipulationsbibliothek) und Ractive.js.

Ractive erfordert nicht, die gesamte Seite SPA zu widmen, sodass wir einige statische Inhalte haben können. Dieser besteht in unserem Fall aus einem Container-Element und dem Seitentitel.

Schließlich laden wir die Daten, die ich für die Demo vorbereitet habe, und das Skript, das unser Programm enthalten wird.

OK, jetzt, da unser HTML-Skelett vorhanden ist, fangen wir an, echte Funktionalität hinzuzufügen.

Liste der Fähigkeiten

Eines der Dinge, die ich an Ractive besonders mag, ist, wie es Ihnen beibringt, über die endgültige Darstellung (HTML) nachzudenken, die Sie erreichen möchten, und es Ihnen dann ermöglicht, sich darauf zu konzentrieren, die notwendigen Code-Bits zu schreiben, um dies zu erreichen.

Lassen Sie uns also zuerst eine Liste von Fähigkeiten als unsere anfängliche Ansicht erstellen. Dies bedeutet einfach:

  • Hinzufügen eines HTML-Elements, in dem die Skill-Liste angezeigt wird.
  • Hinzufügen eines kleinen Ausschnitts des Vorlagencodes zu unserem HTML.
  • Schreiben Sie ein kurzes und einfaches JavaScript, das die Daten an die Vorlage liefert, um sie in dem von uns hinzugefügten HTML-Element zu rendern.

Die Mods für das HTML bestehen aus Folgendem:

 <div class="container"> <h1>Toptal Search</h1> <div></div> <!-- THIS IS THE NEW HTML ELEMENT --> </div> <!-- THIS IS THE SMALL SNIPPET OF TEMPLATE CODE --> <script type="text/html"> <div class="row"> {{#each skills}} <span class="col-xs-3"> <a href="#" class="label label-primary">{{this}}</a> </span> {{/each}} </div> </script>

Es gibt keine spezielle Konvention mit Ractive, um das HTML-Element anzugeben, das die anzuzeigenden Daten erhalten soll, aber der einfachste Weg, dies zu tun, besteht darin, dem Element eine ID hinzuzufügen. Normalerweise verwende ich für diesen Zweck die „Root“-ID. Wir werden bald sehen, wie es verwendet wird, wenn Ractive initialisiert wird. Für Neugierige gibt es andere Möglichkeiten, das Wurzelelement anzugeben.

Das etwas umständliche script-Element mit type="text/html" ist ein cleverer Trick, um einen HTML-Block vom Browser laden zu lassen, ohne dass er geparst oder gerendert wird, da Browser Skripte unbekannten Typs ignorieren. Der Inhalt des Skripts ist eine Schnurrbart/Lenker-ähnliche Vorlage (obwohl Ractive einige Erweiterungen hat).

Wir schreiben zuerst den Vorlagencode unter der Annahme, dass wir Zugriff auf das Skills-Array haben. Wir verwenden die Schnurrbart-Direktive {{#each}} , um die Iteration zu definieren. Innerhalb der Direktive kann auf das aktuelle Element als this zugegriffen werden. Auch hier gehen wir davon aus, dass die Skills-Variable ein Array von Strings enthält, also rendern wir sie einfach mit einem Interpolations-Schnurrbart {{this}} .

OK, das ist der HTML-Code. Aber was ist mit dem JavaScript? Hier passiert die „Magie“, die die Daten an die Vorlage liefert:

 (function () { var skills = DB.skills, developers = DB.developers; var app = new Ractive({ el: '#root', template: '#tpl-app', data: { skills: _.keys(DB.skills) } }); }());

Beeindruckend, oder? In nur diesen 10 Codezeilen können wir:

  1. „Abrufen“ der Daten aus der „DB“.
  2. Instanziieren Sie eine neue Ractive-App.
  3. Sagen Sie ihm, dass es innerhalb des Elements mit rendern soll .
  4. Sagen Sie ihm, dass es ein Skriptelement mit verwenden soll um die Vorlage zu erhalten (es gibt auch andere Möglichkeiten).
  5. Übergeben Sie Anfangsdaten (wir werden sehen, wie sie zur Laufzeit geändert werden) oder „Scope“, wenn Sie an die Angular-Terminologie gewöhnt sind.
  6. Verwenden Sie die Lodash- keys , um die Skills-Namen zu erhalten, die wir als Objektschlüssel in der „DB“ verwenden.

Mit diesem Skript sagen wir also dem Framework, was es tun soll, aber nicht, wie es es tun soll. Die Vorlage erklärt wie, was ich persönlich ziemlich erstaunlich und natürlich finde.

Hoffentlich fangen Sie an, die Idee zu verstehen, also lassen Sie uns jetzt etwas Nützlicheres zusätzlich zu dem, was wir haben, implementieren.

Fähigkeitensuche

Die Suchseite benötigt natürlich ein Suchfeld. Und wir möchten, dass es eine interaktive Funktion bereitstellt, bei der die Liste der Fähigkeiten, wenn der Benutzer in das Suchfeld eingibt, nach unten gefiltert wird und nur diejenigen enthält, die die eingegebene Teilzeichenfolge enthalten (wobei die Filterung ohne Berücksichtigung der Groß- und Kleinschreibung erfolgt).

Wie bei Ractive üblich, beginnen wir mit der Definition des Templates (während wir darüber nachdenken, welche neuen Kontextvariablen benötigt werden und was sich in Bezug auf die Datenverwaltung ändern würde):

 <div class="container"> <h1>Toptal Search</h1> <div></div> </div> <!-- THIS IS THE SMALL SNIPPET OF TEMPLATE CODE --> <script type="text/html"> <!-- HERE'S OUR SEARCH BOX --> <div class="row"> <form class="form-horizontal col-xs-6 col-xs-offset-6"> <input type="search" class="form-control" value="{{ skillFilter }}" placeholder="Type part of the skill name here"> </form> </div> <hr> <!-- NOW INSTEAD OF DISPLAYING ALL SKILLS, WE INVOKE A TO-BE-CREATED JAVASCRIPT skills() FUNCTION THAT WILL FILTER THE SKILL LIST DOWN TO THOSE THAT MATCH THE TEXT ENTERED BY THE USER --> <div class="row"> {{#each skills()}} <span class="col-xs-3"> <a href="#" class="label label-primary">{{this}}</a> </span> {{/each}} </div> </script>

Nicht so viele Änderungen, aber immer noch eine ganze Menge zu lernen.

Zuerst haben wir ein neues <div> hinzugefügt, das unser Suchfeld enthält. Es ist ziemlich offensichtlich, dass wir diese Eingabe mit einer Variablen verbinden möchten (es sei denn, Sie sind nostalgisch in Bezug auf die guten alten jQuery-Suppentage). Ractive unterstützt die sogenannte Zwei-Wege-Bindung, was bedeutet, dass Ihr JS-Code einen Wert abrufen kann, ohne ihn manuell aus dem DOM lesen zu müssen. In unserem Fall wird dies durch die Verwendung der Interpolation value="{{ skillFilter }}" . Ractive versteht, dass wir diese Variable an das Wertattribut der Eingabe binden wollen. Es überwacht also die Eingabe für uns und aktualisiert die Variable automatisch. Ziemlich ordentlich mit nur 1 Zeile HTML.

Zweitens, wie im obigen Kommentar im Code-Snippet erläutert, erstellen wir jetzt, anstatt alle Fähigkeiten anzuzeigen, eine skills() JS-Funktion, die die Skill-Liste filtert und nur diejenigen zurückgibt, die mit dem vom Benutzer eingegebenen Text übereinstimmen:

 // store skill list in a variable outside of Ractive scope var skillNames = _.keys(DB.skills); var app = new Ractive({ el: '#root', template: '#tpl-app', data: { // initializing the context variable is not strictly // required, but it is generally considered good practice skillFilter: null, // Define the skills() function right in our data object. // Function is available to our template where we call it. skills: function() { // Get the skillFilter variable from the Ractive instance // (available as 'this'). // NOTE WELL: Our use of a getter here tells Ractive that // our function has a *dependency* on the skillFilter // value, so this is significant. var skillFilter = this.get('skillFilter'); if (!skillFilter) { return skillNames; } skillFilter = new RegExp(_.escapeRegExp(skillFilter), 'i') return _.filter(skillNames, function(skill) { return skill.match(skillFilter); }); } } });

Obwohl dies sauber und einfach zu implementieren ist, fragen Sie sich vielleicht, wie sich dies auf die Leistung auswirkt. Ich meine, wir werden jedes Mal eine Funktion aufrufen? Nun, jedes Mal was? Ractive ist clever genug, nur Teile des Templates neu zu rendern (und alle Funktionen von ihnen aufzurufen), wenn sich ihre Abhängigkeiten (Variablen) ändern (Ractive weiß dank der Verwendung von Settern, wann das passiert).

Übrigens, für diejenigen, die daran interessiert sind, noch einen Schritt weiter zu gehen, gibt es auch eine elegantere Möglichkeit, dies mit einer berechneten Eigenschaft zu tun, aber ich überlasse es Ihnen, damit zu spielen, wenn Sie möchten.

Die Ergebnisseite

Nachdem wir nun eine ziemlich brauchbare, durchsuchbare Skill-Liste haben, gehen wir weiter zur Ergebnisansicht, wo die passende Liste der Entwickler angezeigt wird.

Wechseln zur und von der Skill-Ansicht

Es gibt offensichtlich mehrere Möglichkeiten, wie dies implementiert werden könnte. Ich habe den Ansatz gewählt, dass es zwei unterschiedliche Ansichten gibt, je nachdem, ob eine Fertigkeit ausgewählt wurde oder nicht. Wenn ja, zeigen wir die Liste der passenden Entwickler; wenn nicht, zeigen wir die Fähigkeitsliste und das Suchfeld.

Also, für den Anfang, wenn der Benutzer einen Fertigkeitsnamen auswählt (dh darauf klickt), muss die Fertigkeitsliste ausgeblendet werden und der Fertigkeitsname sollte stattdessen als Seitenüberschrift angezeigt werden. Umgekehrt muss es in der ausgewählten Skill-Ansicht eine Möglichkeit geben, diese Ansicht zu schließen und zur Liste der Skills zurückzukehren.

Hier ist unser erster Schritt auf diesem Weg:

 <script type="text/html"> <!-- PARTIAL IS A NEW CONCEPT HERE --> {{#partial skillsList}} <div class="row"> <form class="form-horizontal col-xs-6 col-xs-offset-6"> <input type="search" class="form-control" value="{{ skillFilter }}" placeholder="Type part of the skill name here"> </form> </div> <hr> <div class="row"> {{#each skills()}} <span class="col-xs-3"> <!-- MAKE OUR SKILLS CLICKABLE, USING PROXY EVENTS --> <a href="#" class="label label-primary" on-click="select-skill:{{this}}">{{this}}</a> </span> {{/each}} </div> {{/partial}} {{#partial skillView}} <h2> <!-- DISPLAY SELECTED SKILL AS HEADING ON THE PAGE --> {{ currentSkill }} <!-- CLOSE BUTTON TAKES USER BACK TO SKILLS LIST --> <button type="button" class="close pull-right" on-click="deselect-skill">&times; CLOSE</button> </h2> {{/partial}} <!-- PARTIALS ARE NOT IN THE VIEW UNTIL WE EXPLICITLY INCLUDE THEM, SO INCLUDE THE PARTIAL RELEVANT TO THE CURRENT VIEW. --> {{#if currentSkill}} {{> skillView}} {{else}} {{> skillsList}} {{/if}} </script>

OK, hier passiert eine Menge.

Um dies als zwei verschiedene Ansichten implementieren zu können, habe ich zunächst alles, was wir bisher hatten (dh die Listenansicht), in eine sogenannte Teilansicht verschoben. Ein Partial ist im Wesentlichen ein Teil des Vorlagencodes, den wir (bald) an anderer Stelle einfügen werden.

Dann möchten wir unsere Skills anklickbar machen und wenn es angeklickt wird, möchten wir zur entsprechenden Skill-Ansicht navigieren. Dafür verwenden wir sogenannte Proxy-Ereignisse, wobei wir auf ein physisches Ereignis reagieren (Klick, der Name ist der, der von Ractive verstanden wird) und es an das logische Ereignis weiterleiten (Select-Skill, der Name ist, wie wir es nennen ) Übergeben des Arguments (wie Sie sich wahrscheinlich erinnern, steht dies hier für den Skill-Namen).

(FYI, es gibt eine alternative Syntax von Methodenaufrufen, um dasselbe zu erreichen.)

Als nächstes nehmen wir (erneut) an, dass wir eine Variable namens currentSkill haben, die den Namen der ausgewählten Fähigkeit (falls vorhanden) enthält oder leer ist, wenn keine Fähigkeiten ausgewählt sind. Also definieren wir einen weiteren Partial, der den aktuellen Skill-Namen anzeigt und auch einen „CLOSE“-Link hat, der den Skill abwählen soll.

Für das JavaScript ist die Hauptergänzung der Code zum Abonnieren der select-skill- und deselekt-skill-Ereignisse, currentSkill (und skillFilter ) entsprechend aktualisiert werden:

 var app = new Ractive({ el: '#root', template: '#tpl-app', data: { skillFilter: null, currentSkill: null, // INITIALIZE currentSkill TO null // skills function remains unchanged skills: function() { var skillFilter = this.get('skillFilter'); if (!skillFilter) { return skillNames; } skillFilter = new RegExp(_.escapeRegExp(skillFilter), 'i') return _.filter(skillNames, function(skill) { return skill.match(skillFilter); }); } } }); // SUBSCRIBE TO LOGICAL EVENT select-skill app.on('select-skill', function(event, skill) { this.set({ // SET currentSkill TO THE SKILL SELECTED BY THE USER currentSkill: skill, // RESET THE SEARCH FILTER skillFilter: null }); }); // SUBSCRIBE TO LOGICAL EVENT deselect-skill app.on('deselect-skill', function(event) { this.set('currentSkill', null); // CLEAR currentSkill });

Auflisten von Entwicklern für jede Fähigkeit

Nachdem wir die neue Ansicht für die Fertigkeit vorbereitet haben, können wir jetzt etwas Fleisch hinzufügen – die tatsächliche Liste der Entwickler, die wir für diese Liste haben. Dazu erweitern wir das Partial für diese Ansicht wie folgt:

 {{#partial skillView}} <h2> {{ currentSkill }} <button type="button" class="close pull-right" on-click="deselect-skill">&times; CLOSE</button> </h2> {{#each skillDevelopers(currentSkill)}} <div class="panel panel-default"> <div class="panel-body"> {{ this.name }} </div> </div> {{/each}} {{/partial}}

Hoffentlich bekommen Sie zu diesem Zeitpunkt ein Gefühl dafür, was hier vor sich geht: Wir haben unserem skillView Teil einen neuen Iterationsabschnitt hinzugefügt, der über das Ergebnis einer neuen skillDevelopers Funktion iteriert, die wir gleich als Nächstes schreiben werden. Für jeden Entwickler im Array (zurückgegeben von dieser skillDevelopers Funktion) rendern wir ein Panel und zeigen den Namen des Entwicklers an. Beachten Sie, dass ich hier die implizite Form {{name}} verwenden könnte und Ractive das richtige Attribut finden würde, indem es die Kontextkette ab dem aktuellen Kontext durchsucht (was in unserem Fall das durch {{#each}} gebundene Entwicklerobjekt ist), aber Ich bin lieber explizit. Weitere Informationen zu Kontexten und Verweisen finden Sie in der Ractive-Dokumentation.

Und hier ist die Implementierung der Funktion skillDevelopers() :

 skillDevelopers: function(skill) { // GET THE SKILL OBJECT FROM THE “DB” skill = skills[skill]; // SAFETY CHECK, RETURN EARLY IN CASE OF UNKNOWN SKILL NAME if (!skill) { return; } // MAP THE DEVELOPER'S IDs (SLUGS) TO THE // ACTUAL DEVELOPER DETAIL OBJECTS return _.map(skill.developers, function(slug) { return developers[slug]; }); }

Erweitern des Eintrags für jeden Entwickler

Jetzt, da wir eine Arbeitsliste von Entwicklern haben, ist es an der Zeit, weitere Details und natürlich ein schönes Foto hinzuzufügen:

 {{#partial skillView}} <h2> {{ currentSkill }} <button type="button" class="close pull-right" on-click="deselect-skill">&times; CLOSE</button> </h2> {{#each skillDevelopers(currentSkill)}} <div class="panel panel-default"> <div class="panel-body media"> <div class="media-left"> <!-- ADD THE PHOTO --> <img class="media-object img-circle" width="64" height="64" src="{{ this.photo }}" alt="{{ this.name }}"> </div> <div class="media-body"> <!-- MAKE THE DEVELOPER'S NAME A HYPERLINK TO THEIR PROFILE --> <a class="h4 media-heading" href="{{ this.url }}" target="_blank"> {{ this.name }}</a> <!-- ADD MORE DETAILS (FROM THEIR PROFILE) --> <p>{{ this.desc }}</p> </div> </div> </div> {{/each}} {{/partial}}

Nichts Neues hier von der Ractive-Seite der Dinge, aber eine etwas stärkere Nutzung von Bootstrap-Funktionen.

Anzeigen einer anklickbaren Liste von Entwicklerfähigkeiten

Wir haben bisher gute Fortschritte gemacht, aber ein Merkmal, das noch fehlt, ist die andere Seite der Beziehung zwischen Fähigkeiten und Entwicklern. wir wollen nämlich die Skills jedes Entwicklers anzeigen und wir wollen, dass jeder dieser Skills ein anklickbarer Link ist, der uns zur Ergebnisansicht für diesen Skill führt.

Aber warte… Ich bin mir sicher, dass wir genau das Gleiche bereits in der Skills-Liste haben. Ja, das tun wir tatsächlich. Es befindet sich in der anklickbaren Liste der Fähigkeiten, aber das kommt aus einem anderen Array als die Fähigkeiten jedes Entwicklers. Diese sind sich jedoch so ähnlich, dass es für mich ein klares Zeichen dafür ist, dass wir diesen HTML-Teil wiederverwenden sollten. Und zu diesem Zweck sind Teiltöne unser Freund.

(Hinweis: Ractive hat auch einen fortgeschritteneren Ansatz für wiederverwendbare Teile einer Ansicht, bekannt als Komponenten. Sie sind wirklich sehr nützlich, aber der Einfachheit halber werden wir sie jetzt nicht diskutieren.)

So erreichen wir dies mit Partials (und beachten Sie übrigens, dass wir diese Funktionalität hinzufügen können, ohne eine einzige Zeile JavaScript-Code hinzuzufügen!):

 <!-- MAKE THE CLICKABLE SKILL LINK INTO ITS OWN “skill” PARTIAL --> {{#partial skill}} <a href="#" class="label label-primary" on-click="select-skill:{{this}}">{{this}}</a> {{/partial}} {{#partial skillsList}} <div class="row"> <form class="form-horizontal col-xs-6 col-xs-offset-6"> <input type="search" class="form-control" value="{{ skillFilter }}" placeholder="Type part of the skill name here"> </form> </div> <hr> <div class="row"> {{#each skills()}} <!-- USE THE NEW “skill” PARTIAL --> <span class="col-xs-3">{{> skill}}</span> {{/each}} </div> {{/partial}} {{#partial skillView}} <h2> {{ currentSkill }} <button type="button" class="close pull-right" on-click="deselect-skill">&times; CLOSE</button> </h2> {{#each skillDevelopers(currentSkill)}} <div class="panel panel-default"> <div class="panel-body media"> <div class="media-left"> <img class="media-object img-circle" width="64" height="64" src="{{ this.photo }}" alt="{{ this.name }}"> </div> <div class="media-body"> <a class="h4 media-heading" href="{{ this.url }}" target="_blank">{{ this.name }}</a> <p>{{ this.desc }}</p> <p> <!-- ITERATE OVER THE DEVELOPER'S SKILLS --> {{#each this.skills}} <!-- REUSE THE NEW “skill” PARTIAL TO DISPLAY EACH DEVELOPER SKILL AS A CLICKABLE LINK --> {{> skill}}&nbsp; {{/each}} </p> </div> </div> </div> {{/each}} {{/partial}}

Ich habe die Skills-Liste bereits an das Objekt des Entwicklers angehängt, das wir aus der „DB“ abgerufen haben, also habe ich die Vorlage nur ein wenig geändert: Ich habe die Zeile, die das Skill-Label darstellt, in einen Teil verschoben und diesen Teil dort verwendet, wo sich diese Zeile ursprünglich befand.

Wenn ich dann über die Fähigkeiten des Entwicklers iteriere, kann ich denselben neuen Teil wiederverwenden, um jede dieser Fähigkeiten auch als anklickbaren Link anzuzeigen. Darüber hinaus stellt dies auch das select-skill-Ereignis dar, wenn Sie sich erinnern, und übergibt denselben Skill-Namen. Das bedeutet, dass wir dies überall einfügen können (mit dem richtigen Kontext) und wir erhalten ein anklickbares Label, das zur Skill-Ansicht führt!

Letzter Schliff – Preloader

OK, wir haben jetzt eine grundlegende funktionale App. Es ist sauber und arbeitet schnell, aber es dauert immer noch einige Zeit zum Laden. (In unserem Fall liegt dies teilweise daran, dass wir nicht verkettete, nicht minimierte Quellen verwenden, aber in einer realen App kann es andere wichtige Gründe geben, z. B. das Laden von Anfangsdaten).

Als letzten Schritt zeige ich Ihnen einen netten Trick, um eine Vorladeanimation hinzuzufügen, die entfernt wird, sobald Ractive unsere App rendert:

 <div class="container"> <h1>Toptal Search</h1> <div> <div class="progress"> <div class="progress-bar progress-bar-striped active"> Loading... </div> </div> </div> </div>

Also, was ist die Magie hier? Es ist eigentlich ganz einfach. Ich habe etwas Inhalt (es ist ein animierter Bootstrap-Fortschrittsbalken, aber es könnte auch ein animiertes GIF oder was auch immer sein) direkt zu unserem Stammelement hinzugefügt. Ich denke, es ist ziemlich clever – während unsere Skripte geladen werden, sieht der Benutzer die Ladeanzeige (da sie keine Abhängigkeit vom JavaScript hat, kann sie sofort angezeigt werden). Sobald die Ractive-App jedoch initialisiert wird, überschreibt Ractive den Inhalt des Root-Elements (und löscht dadurch die vorab geladene Animation) mit der gerenderten Vorlage. Auf diese Weise können wir diesen Effekt mit nur einem Stück statischem HTML und 0 Zeilen Logik erzielen. Ich finde das ziemlich cool.

Fazit

Denken Sie darüber nach, was wir hier erreicht haben und wie einfach wir es erreicht haben. Wir haben eine ziemlich umfassende App: Sie zeigt eine Liste von Fähigkeiten an, ermöglicht ein schnelles Durchsuchen (und unterstützt sogar die interaktive Aktualisierung der Fähigkeitenliste, wenn der Benutzer in das Suchfeld eintippt), ermöglicht das Navigieren zu einer bestimmten Fähigkeit und zurück und Listen die Entwickler für jede ausgewählte Fertigkeit. Darüber hinaus können wir auf jede von einem beliebigen Entwickler aufgelistete Fähigkeit klicken, um zur Liste der Entwickler mit dieser Fähigkeit zu gelangen. Und das alles mit weniger als 80 Zeilen HTML und weniger als 40 Zeilen JavaScript. Meiner Meinung nach ist das ziemlich beeindruckend und spricht Bände über die Kraft, Eleganz und Einfachheit von Ractive.

Eine funktionierende Version der App ist hier online verfügbar und der vollständige Quellcode ist öffentlich und hier verfügbar.

Natürlich haben wir in diesem Artikel nur an der Oberfläche dessen gekratzt, was mit dem Ractive-Framework möglich ist. Wenn Ihnen gefällt, was Sie bisher gesehen haben, empfehle ich Ihnen dringend, mit Ractives 60-Sekunden-Setup zu beginnen und selbst zu erkunden, was Ractive zu bieten hat.