Ractive.js — proste aplikacje internetowe

Opublikowany: 2022-03-11

W dzisiejszym szybko rozrastającym się środowisku frameworków i bibliotek JavaScript, wybór tej, na której chcesz oprzeć swój program, może być nie lada wyzwaniem. W końcu, gdy już przejdziesz ścieżką korzystania z określonego frameworka, migracja kodu do korzystania z innego jest nietrywialnym zadaniem, na które możesz nigdy nie mieć czasu ani budżetu.

Dlaczego więc Ractive.js?

W przeciwieństwie do innych narzędzi generujących obojętny kod HTML, Ractive przekształca szablony w plany aplikacji, które są domyślnie interaktywne. I chociaż można z pewnością argumentować, że wkład Ractive jest bardziej ewolucyjny niż rewolucyjny, jego wartość jest jednak znacząca.

To, co sprawia, że ​​Ractive jest tak użyteczny, to to, że zapewnia potężne możliwości, ale robi to w sposób, który jest odświeżająco prosty w użyciu dla programisty. Co więcej, jest dość elegancki, szybki, dyskretny i mały.

W tym artykule omówimy proces tworzenia prostej aplikacji wyszukiwania Ractive, demonstrując niektóre kluczowe funkcje Ractive oraz sposoby, w jakie pomaga ona uprościć aplikacje internetowe i programowanie.

Ractive.js i aplikacje internetowe

Co to jest Ractive.js?

Ractive został pierwotnie stworzony, aby rozwiązać problem wiązania danych w bardziej elegancki sposób. W tym celu pobiera szablony i przekształca je w lekką wirtualną reprezentację DOM, dzięki czemu, gdy dane się zmieniają, prawdziwy DOM jest aktualizowany inteligentnie i wydajnie.

Ale wkrótce stało się jasne, że podejście i infrastrukturę zastosowane przez Ractive można wykorzystać również do robienia innych rzeczy bardziej efektywnie. Może na przykład automatycznie zająć się takimi rzeczami, jak ponowne używanie programów obsługi zdarzeń i automatyczne usuwanie ich, gdy nie są już potrzebne. Delegowanie wydarzeń staje się zbędne. Podobnie jak w przypadku powiązania danych, to podejście zapobiega nieporęcznemu kodowi w miarę rozwoju aplikacji.

Kluczowe funkcje, takie jak dwukierunkowe wiązanie, animacje i obsługa SVG, są dostarczane od razu po zainstalowaniu, a niestandardowe funkcje można łatwo dodać za pomocą wtyczek.

Podczas gdy niektóre narzędzia i struktury zmuszają Cię do nauki nowego słownictwa i struktury aplikacji w określony sposób, Ractive działa dla Ciebie, a nie na odwrót. Dobrze integruje się również z innymi bibliotekami.

Nasza przykładowa aplikacja

Nasza przykładowa aplikacja będzie używana do przeszukiwania bazy danych programistów Toptal na podstawie umiejętności. Nasza aplikacja będzie miała dwa widoki:

  • Wyszukiwanie: lista umiejętności z wbudowanym polem wyszukiwania
  • Wyniki: widok umiejętności wraz z listą programistów

Dla każdego dewelopera wyświetlimy jego nazwę, zdjęcie, krótki opis oraz listę umiejętności (każda umiejętność będzie linkowała do odpowiedniego widoku umiejętności).

(Uwaga: łącza do działającego wystąpienia aplikacji online i repozytorium kodu źródłowego znajdują się na końcu tego artykułu).

Aby utrzymać nasz główny nacisk na framework Ractive, zastosujemy szereg uproszczeń, których normalnie nie powinno się robić w środowisku produkcyjnym:

  • Domyślny motyw. Do stylizacji użyjemy Bootstrapa z domyślnym motywem, zamiast dostosowywać motyw do stylu Twojej aplikacji.
  • Zależności. Dodamy nasze zależności jako osobne skrypty, które definiują zmienne globalne (zamiast używać modułów ES6, CommonJS lub AMD z odpowiednim loaderem do rozwoju, a etapem kompilacji do produkcji).
  • Dane statyczne. Wykorzystamy dane statyczne, które przygotowałem poprzez scraping publicznych stron w serwisie Toptal.
  • Brak routingu po stronie klienta. Oznacza to, że adres URL pozostanie taki sam, gdy przełączamy się między widokami. Zdecydowanie nie powinieneś tego robić w przypadku SPA, chociaż może to być OK w przypadku niektórych małych interaktywnych komponentów. Ractive nie ma wbudowanej implementacji routera, ale może być używany z routerami innych firm, jak pokazano w tym przykładzie.
  • Szablony zdefiniowane wewnątrz znaczników skryptu w HTML. Niekoniecznie jest to zły pomysł, zwłaszcza dla małych aplikacji, i ma pewne zalety (jest prosty i możesz przetwarzać te szablony po stronie klienta razem z szablonami po stronie serwera, na przykład w celu internacjonalizacji). Ale w przypadku większych aplikacji możesz skorzystać ze wstępnej kompilacji (czyli wstępnego parsowania szablonów do wewnętrznej reprezentacji JS.

Zacznijmy od aplikacji internetowych

OK, więc powiedziawszy, zacznijmy tworzyć aplikację. Zrobimy to w sposób iteracyjny, dodając kolejne mniejsze funkcje i badając koncepcje w miarę ich napotykania.

Zacznijmy od utworzenia folderu z dwoma plikami w środku: index.html i script.js . Nasza aplikacja będzie niezwykle prosta i będzie działać z protokołem file:// , aby uniknąć konieczności uruchamiania serwera deweloperskiego (choć możesz, jeśli chcesz).

Strona wyszukiwania

Zaczniemy od zaimplementowania strony wyszukiwania, na której użytkownik może wybrać umiejętność, dla której znajdzie pasujących programistów w bazie danych Toptal.

Szkielet HTML

Zacznijmy od tej banalnej strony HTML:

 <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>

Jak widać, to banalny dokument HTML5. Ładuje Bootstrap z CDN, Lodash (niesamowitą bibliotekę do manipulacji danymi) i Ractive.js.

Ractive nie wymaga przeznaczania całej strony na SPA, więc możemy mieć trochę statycznych treści. W naszym przypadku składa się to z elementu kontenera i tytułu strony.

Na koniec wczytujemy dane, które przygotowałem do demonstracji oraz skrypt, który będzie zawierał nasz program.

OK, teraz, gdy nasz szkielet HTML jest na swoim miejscu, zacznijmy dodawać prawdziwą funkcjonalność.

Lista umiejętności

Jedną z rzeczy, które szczególnie lubię w Ractive, jest to, jak uczy Cię myśleć o ostatecznej reprezentacji (HTML), którą chcesz osiągnąć, a następnie pozwala skupić się na pisaniu niezbędnych fragmentów kodu, aby to się stało.

Więc najpierw zbudujmy listę umiejętności jako nasz początkowy widok. Zrobienie tego po prostu pociąga za sobą:

  • Dodanie elementu HTML, w którym będzie wyświetlana lista umiejętności.
  • Dodanie małego fragmentu kodu szablonu do naszego kodu HTML.
  • Napisanie krótkiego i prostego JavaScript, który dostarcza dane do szablonu, aby renderować je w dodanym przez nas elemencie HTML.

Mody do HTML składają się z następujących elementów:

 <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>

Nie ma specjalnej konwencji w Ractive określającej element HTML, który ma otrzymać dane do wyświetlenia, ale najprostszym sposobem na to jest dodanie identyfikatora do elementu. Zwykle używam w tym celu identyfikatora „root”. Wkrótce zobaczymy, jak jest używany po zainicjowaniu Ractive. Dla ciekawskich istnieją inne sposoby określenia elementu głównego.

Nieco niezręczny element skryptu z type="text/html" to sprytna sztuczka, aby pobrać fragment kodu HTML ładowany przez przeglądarkę bez jego analizy lub renderowania, ponieważ przeglądarki ignorują skrypty nieznanego typu. Zawartość skryptu jest szablonem podobnym do wąsów/kierownic (chociaż Ractive ma pewne rozszerzenia).

Najpierw piszemy kod szablonu zakładając, że mamy dostęp do tablicy umiejętności. Do zdefiniowania iteracji używamy dyrektywy {{#each}} wąsów. Wewnątrz dyrektywy do bieżącego elementu można uzyskać dostęp jako this . Ponownie zakładamy, że zmienna umiejętności zawiera tablicę łańcuchów, więc po prostu renderujemy ją z wąsem interpolacyjnym {{this}} .

OK, to jest HTML. Ale co z JavaScriptem? Tutaj dzieje się „magia”, która dostarcza dane do szablonu:

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

Imponujące, nie? W zaledwie 10 linijkach kodu jesteśmy w stanie:

  1. „Pobierz” dane z „DB”.
  2. Utwórz wystąpienie nowej aplikacji Ractive.
  3. Powiedz mu, aby renderował wnętrze elementu za pomocą .
  4. Powiedz mu, aby użył elementu skryptu z aby uzyskać szablon (istnieją również inne sposoby na zrobienie tego).
  5. Przekaż dane początkowe (zobaczymy, jak to zmienić w czasie wykonywania) lub „zakres”, jeśli jesteś przyzwyczajony do terminologii Angular.
  6. Użyj metody lodash keys , aby uzyskać nazwy umiejętności, których używamy jako kluczy obiektowych w „DB”.

Więc w zasadzie za pomocą tego skryptu mówimy frameworkowi, co ma zrobić, ale nie mówimy, jak to zrobić. Szablon deklaruje sposób, co osobiście uważam za niesamowite i naturalne.

Mam nadzieję, że zaczynasz rozumieć ten pomysł, więc teraz zaimplementujmy coś bardziej przydatnego do tego, co mamy.

Wyszukiwanie umiejętności

Strona wyszukiwania oczywiście potrzebuje pola wyszukiwania. Chcielibyśmy, aby zapewniał interaktywną możliwość, dzięki której podczas wpisywania przez użytkownika w polu wyszukiwania lista umiejętności jest filtrowana i obejmuje tylko te, które zawierają wprowadzony podciąg (przy filtrowaniu bez uwzględniania wielkości liter).

Jak zwykle w Ractive zaczynamy od zdefiniowania szablonu (zastanawiając się, jakie nowe zmienne kontekstowe będą potrzebne, a co zmieni się w zakresie zarządzania danymi):

 <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>

Niewiele zmian, ale wciąż sporo do nauczenia.

Najpierw dodaliśmy nowy element <div> zawierający nasze pole wyszukiwania. Jest całkiem oczywiste, że chcemy połączyć to wejście z jakąś zmienną (chyba że jesteś nostalgią za starymi, dobrymi czasami zup jQuery). Ractive obsługuje tak zwane wiązanie dwukierunkowe, co oznacza, że ​​Twój kod JS może pobrać wartość bez konieczności ręcznego odczytywania jej z DOM. W naszym przypadku jest to realizowane za pomocą interpolacji wąsów value="{{ skillFilter }}" . Ractive rozumie, że chcemy powiązać tę zmienną z atrybutem value danych wejściowych. Więc obserwuje za nas dane wejściowe i automatycznie aktualizuje zmienną. Całkiem schludny z zaledwie 1 wierszem kodu HTML.

Po drugie, jak wyjaśniono w komentarzu we fragmencie kodu powyżej, teraz zamiast wyświetlać wszystkie umiejętności, utworzymy funkcję JS skills() , która będzie filtrować listę umiejętności i zwracać tylko te, które pasują do tekstu wprowadzonego przez użytkownika:

 // 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); }); } } });

Chociaż jest to przejrzyste i proste w implementacji, możesz zastanawiać się, jak wpłynie to na wydajność. Mam na myśli, że będziemy wywoływać funkcję za każdym razem? Cóż, za każdym razem co? Ractive jest wystarczająco sprytny, aby ponownie renderować części szablonu (i wywoływać z nich dowolne funkcje), gdy zmieniają się ich zależności (zmienne) (Ractive wie, kiedy to się dzieje, dzięki użyciu seterów).

Nawiasem mówiąc, dla tych, którzy chcą pójść o krok dalej, istnieje również bardziej elegancki sposób na zrobienie tego za pomocą właściwości obliczonej, ale zostawię to wam do samodzielnej zabawy, jeśli chcecie.

Strona wyników

Teraz, gdy mamy całkiem użyteczną listę umiejętności, którą można przeszukiwać, przejdźmy do widoku wyników, w którym zostanie wyświetlona lista pasujących programistów.

Przełączanie do i z widoku umiejętności

Jest oczywiście wiele sposobów na realizację tego. Wybrałem podejście polegające na tym, że istnieją dwa różne poglądy w zależności od tego, czy wybrano umiejętność, czy nie. Jeśli tak, pokazujemy listę pasujących programistów; jeśli nie, pokazujemy listę umiejętności i pole wyszukiwania.

Tak więc, na początek, kiedy użytkownik wybierze (tj. kliknie) nazwę umiejętności, lista umiejętności musi być ukryta, a nazwa umiejętności powinna być pokazana jako nagłówek strony. I odwrotnie, w wybranym widoku umiejętności musi istnieć sposób na zamknięcie tego widoku i powrót do listy umiejętności.

Oto nasz pierwszy krok na tej ścieżce:

 <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, DUŻO się tu dzieje.

Po pierwsze, aby zaimplementować to jako dwa różne widoki, przeniosłem wszystko, co mieliśmy do tej pory (tj. widok listy) do czegoś, co nazywa się częściowym. Podszablona to zasadniczo fragment kodu szablonu, który zamierzamy umieścić w innym miejscu (wkrótce).

Następnie chcemy, aby nasze umiejętności były klikalne, a po kliknięciu chcemy przejść do odpowiedniego widoku umiejętności. W tym celu używamy czegoś, co nazywamy zdarzeniami proxy, w których reagujemy na zdarzenie fizyczne (po kliknięciu, nazwa jest zrozumiała dla Ractive) i przekazujemy je do zdarzenia logicznego (select-skill, nazwa jest tak, jak ją nazwiemy ) przekazując argument (jak zapewne pamiętasz, oznacza to tutaj nazwę umiejętności).

(FYI, alternatywna składnia wywołań metod istnieje, aby osiągnąć to samo).

Następnie zakładamy (ponownie), że będziemy mieć zmienną o nazwie currentSkill , która będzie zawierała nazwę wybranej umiejętności (jeśli istnieje) lub będzie pusta, jeśli żadna umiejętność nie zostanie wybrana. Zdefiniujemy więc inną część, która pokazuje aktualną nazwę umiejętności, a także ma łącze „ZAMKNIJ”, które powinno odznaczyć umiejętność.

W przypadku JavaScript głównym dodatkiem jest kod do subskrybowania zdarzeń select-skill i deselect-skill, odpowiednio aktualizując currentSkill (i skillFilter ):

 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 });

Lista programistów dla każdej umiejętności

Po przygotowaniu nowego widoku umiejętności możemy teraz dodać trochę mięsa — rzeczywistą listę deweloperów, którą mamy dla tej listy. W tym celu rozwijamy częściowe dla tego widoku w następujący sposób:

 {{#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}}

Mam nadzieję, że w tym momencie poczujesz, co się tutaj dzieje: dodaliśmy nową sekcję iteracji do naszej części skillView , która iteruje nad wynikiem nowej funkcji skillDevelopers , którą napiszemy zaraz obok. Dla każdego dewelopera w tablicy (zwracanej przez tę funkcję skillDevelopers ) renderujemy panel i wyświetlamy nazwę dewelopera. Zauważ, że mógłbym tutaj użyć niejawnej formy {{name}} , a Ractive znalazłby odpowiedni atrybut, przeszukując łańcuch kontekstu zaczynając od bieżącego kontekstu (który w naszym przypadku jest obiektem deweloperskim powiązanym przez {{#each}} ), ale Wolę być jednoznaczny. Więcej informacji na temat kontekstów i odniesień można znaleźć w dokumentacji Ractive.

A oto implementacja funkcji 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]; }); }

Rozszerzanie wpisu dla każdego programisty

Teraz, gdy mamy już roboczą listę programistów, czas dodać więcej szczegółów i oczywiście ładne zdjęcie:

 {{#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}}

Nic nowego od strony Ractive, ale nieco cięższe wykorzystanie funkcji Bootstrap.

Wyświetlanie klikalnej listy umiejętności programisty

Do tej pory osiągnęliśmy spore postępy, ale jedną z funkcji, której wciąż brakuje, jest druga strona relacji między programistami a umiejętnościami; mianowicie chcemy wyświetlać umiejętności każdego programisty i chcemy, aby każda z tych umiejętności była klikalnym łączem, które prowadzi nas do widoku wyników dla tej umiejętności.

Ale poczekaj… jestem pewien, że mamy już dokładnie to samo na liście umiejętności. Tak, w rzeczywistości robimy. Znajduje się na liście umiejętności, którą można kliknąć, ale pochodzi z innej tablicy niż zestaw umiejętności każdego programisty. Są one jednak na tyle podobne, że jest to dla mnie wyraźny znak, że powinniśmy ponownie wykorzystać ten kawałek HTML. I pod tym względem naszym przyjacielem są częściowe.

(Uwaga: Ractive ma również bardziej zaawansowane podejście do fragmentów widoku wielokrotnego użytku, znanych jako komponenty. Są one naprawdę bardzo przydatne, ale dla uproszczenia nie będziemy ich teraz omawiać.)

A więc oto jak osiągamy to za pomocą podszablonów (i zauważ, nawiasem mówiąc, że jesteśmy w stanie dodać tę funkcjonalność bez dodawania ani jednej linii kodu JavaScript!):

 <!-- 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}}

Mam już listę umiejętności dołączoną do obiektu dewelopera, który pobraliśmy z „DB”, więc po prostu zmieniłem nieco szablon: przeniosłem wiersz, który renderuje etykietę umiejętności, do podszablonu i użyłem tego podszablonu w miejscu, w którym pierwotnie znajdował się ten wiersz.

Następnie, gdy przejdę przez umiejętności programisty, mogę ponownie użyć tej samej nowej części, aby wyświetlić każdą z tych umiejętności również jako klikalny link. Co więcej, jeśli pamiętasz, jest to również proxy dla zdarzenia wyboru umiejętności, przekazując tę ​​samą nazwę umiejętności. Oznacza to, że możemy umieścić to w dowolnym miejscu (mając odpowiedni kontekst), a otrzymamy klikalną etykietę, która prowadzi do widoku umiejętności!

Final Touch — Preloader

OK, mamy teraz podstawową funkcjonalną aplikację. Jest czysty i działa szybko, ale ładowanie nadal zajmuje trochę czasu. (W naszym przypadku jest to częściowo spowodowane tym, że korzystamy z niepołączonych, niezminimalizowanych źródeł, ale w rzeczywistej aplikacji mogą istnieć inne ważne powody, takie jak ładowanie danych początkowych).

Jako ostatni krok, pokażę Ci fajną sztuczkę, aby dodać animację wstępnego ładowania, która zostanie usunięta, gdy tylko Ractive wyrenderuje naszą aplikację:

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

Więc na czym polega magia? To całkiem proste. Dodałem trochę treści (jest to animowany pasek postępu Bootstrap, ale może to być animowany GIF lub cokolwiek) prosto do naszego głównego elementu. Myślę, że to całkiem sprytne — podczas ładowania naszych skryptów użytkownik widzi wskaźnik ładowania (ponieważ nie jest on uzależniony od JavaScriptu, może zostać wyświetlony natychmiast). Jednak zaraz po zainicjowaniu aplikacji Ractive, Ractive nadpisze zawartość elementu głównego (a tym samym usunie animację wstępnego ładowania) renderowanym szablonem. W ten sposób jesteśmy w stanie osiągnąć ten efekt tylko kawałek statycznego HTML i 0 linii logicznych. Myślę, że to całkiem fajne.

Wniosek

Pomyśl o tym, co osiągnęliśmy tutaj i jak łatwo to osiągnęliśmy. Mamy dość wszechstronną aplikację: pokazuje listę umiejętności, umożliwia szybkie ich przeszukiwanie (a nawet obsługuje interaktywne aktualizowanie listy umiejętności, gdy użytkownik wpisuje w polu wyszukiwania), umożliwia nawigację do konkretnej umiejętności iz powrotem oraz listy programiści dla każdej wybranej umiejętności. Co więcej, możemy kliknąć dowolną umiejętność wymienioną przez dowolnego programistę, aby przejść do listy programistów z tą umiejętnością. A wszystko to z mniej niż 80 linijkami HTML i mniej niż 40 linijkami JavaScript. Moim zdaniem jest to imponujące i mówi wiele o mocy, elegancji i prostocie Ractive.

Działająca wersja aplikacji jest dostępna online tutaj, a pełny kod źródłowy jest publiczny i dostępny tutaj.

Oczywiście w tym artykule ledwie zarysowaliśmy powierzchnię, co jest możliwe dzięki frameworkowi Ractive. Jeśli podoba Ci się to, co widziałeś do tej pory, gorąco zachęcam do rozpoczęcia 60-sekundowej konfiguracji Ractive i samodzielnego odkrywania wszystkiego, co Ractive ma do zaoferowania.