Ractive.js — веб-приложения стали проще

Опубликовано: 2022-03-11

В сегодняшнем быстро растущем ландшафте фреймворков и библиотек JavaScript выбор той, на которой вы хотите основывать свою разработку, может быть довольно сложной задачей. В конце концов, как только вы пойдете по пути использования определенного фреймворка, перенос вашего кода на использование другого станет нетривиальной задачей, на которую у вас может никогда не хватить времени или бюджета.

Итак, почему Ractive.js?

В отличие от других инструментов, которые генерируют инертный HTML, Ractive преобразует шаблоны в чертежи для приложений, которые по умолчанию являются интерактивными. И хотя можно с уверенностью утверждать, что вклад Ractive скорее эволюционный, чем революционный, тем не менее его ценность значительна.

Что делает Ractive таким полезным, так это то, что он предоставляет мощные возможности, но делает это таким образом, что разработчику очень просто его использовать. Более того, он довольно элегантный, быстрый, ненавязчивый и маленький.

В этой статье мы рассмотрим процесс создания простого поискового приложения Ractive, продемонстрируем некоторые ключевые функции Ractive и то, как оно помогает упростить веб-приложения и разработку.

Ractive.js и веб-приложения

Что такое Ractive.js?

Изначально Ractive был создан для более элегантного решения проблемы привязки данных. С этой целью он берет шаблоны и преобразует их в упрощенное виртуальное представление модели DOM, чтобы при изменении данных реальная модель модели DOM обновлялась разумно и эффективно.

Но вскоре стало очевидно, что подход и инфраструктура, используемые Ractive, можно использовать и для более эффективного решения других задач. Например, он может автоматически позаботиться о таких вещах, как повторное использование обработчиков событий и автоматическое отсоединение их, когда они больше не нужны. Делегирование событий становится ненужным. Как и в случае привязки данных, этот подход предотвращает громоздкость кода по мере роста приложения.

Ключевые функции, такие как двусторонняя привязка, анимация и поддержка SVG, предоставляются «из коробки», а пользовательские функции можно легко добавить с помощью плагинов.

В то время как некоторые инструменты и фреймворки заставляют вас изучать новый словарь и определенным образом структурировать приложение, Ractive работает на вас, а не наоборот. Он также хорошо интегрируется с другими библиотеками.

Наш образец приложения

Наш пример приложения будет использоваться для поиска разработчиков в базе данных Toptal на основе навыков. Наше приложение будет иметь два представления:

  • Поиск: список навыков со встроенным окном поиска
  • Результаты: представление навыков, включая список разработчиков

Для каждого разработчика мы будем отображать его имя, фотографию, краткое описание и список навыков (каждый навык будет связан с соответствующим представлением навыков).

(Примечание. Ссылки на рабочий онлайн-экземпляр приложения и репозиторий исходного кода приведены в конце этой статьи.)

Чтобы сосредоточиться на фреймворке Ractive, мы будем использовать ряд упрощений, которые обычно не следует делать в рабочей среде:

  • Тема по умолчанию. Мы будем использовать Bootstrap с темой по умолчанию для стилизации, а не настраивать тему в соответствии со стилем вашего приложения.
  • Зависимости. Мы добавим наши зависимости в виде отдельных скриптов, определяющих глобальные переменные (вместо использования модулей ES6, CommonJS или AMD с надлежащим загрузчиком для разработки и этапом сборки для производства).
  • Статические данные. Мы будем использовать статические данные, которые я подготовил путем очистки общедоступных страниц на сайте Toptal.
  • Нет маршрутизации на стороне клиента. Это означает, что URL-адрес останется прежним, когда мы переключаемся между представлениями. Вы определенно не должны делать это для SPA, хотя это может быть нормально для некоторых небольших интерактивных компонентов. Ractive не имеет встроенной реализации маршрутизатора, но его можно использовать со сторонними маршрутизаторами, как показано в этом примере.
  • Шаблоны, определенные внутри тегов script в HTML. Это не обязательно плохая идея, особенно для небольших приложений, и у нее есть некоторые преимущества (это просто, и вы можете обрабатывать эти клиентские шаблоны вместе с вашими серверными шаблонами, например, для интернационализации). Но для более крупных приложений вы можете извлечь выгоду из предварительной компиляции (также известной как предварительный анализ шаблонов для внутреннего представления JS.

Начнем с веб-приложений

Итак, с учетом сказанного, давайте начнем создавать приложение. Мы собираемся делать это поэтапно, добавляя меньшие функции одну за другой и исследуя концепции по мере их появления.

Начнем с создания папки с двумя файлами внутри: index.html и script.js . Наше приложение будет предельно простым и будет работать по протоколу file:// , чтобы избежать необходимости запуска сервера разработки (хотя при желании можно).

Страница поиска

Мы начнем с реализации страницы поиска, где пользователь может выбрать навык, для которого нужно найти подходящих разработчиков в базе данных Toptal.

HTML-скелет

Давайте начнем с этой тривиальной 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>

Как видите, это тривиальный документ HTML5. Он загружает Bootstrap из CDN, Lodash (отличная библиотека для работы с данными) и Ractive.js.

Ractive не требует выделения всей страницы SPA, поэтому у нас может быть некоторый статический контент. В нашем случае это элемент контейнера и заголовок страницы.

Наконец, мы загружаем данные, которые я подготовил для демонстрации, и скрипт, который будет содержать нашу программу.

Хорошо, теперь, когда наш HTML-скелет готов, давайте начнем добавлять некоторые реальные функции.

Список навыков

Одна из вещей, которые мне особенно нравятся в Ractive, это то, как он учит вас думать об окончательном представлении (HTML), которого вы хотите достичь, а затем позволяет вам сосредоточиться на написании необходимых битов кода, чтобы это произошло.

Итак, сначала давайте создадим список навыков в качестве нашего первоначального представления. Это просто влечет за собой:

  • Добавление элемента HTML, в котором будет отображаться список навыков.
  • Добавление небольшого фрагмента кода шаблона в наш HTML.
  • Пишем краткий и простой JavaScript, который передает данные в шаблон, чтобы отобразить их в добавленном элементе HTML.

Модификации HTML состоят из следующего:

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

В Ractive нет специального соглашения по указанию HTML-элемента для получения отображаемых данных, но самый простой способ сделать это — добавить идентификатор к элементу. Обычно для этой цели я использую «root» ID. Вскоре мы увидим, как он используется при инициализации Ractive. Для любопытных есть другие способы указать корневой элемент.

Немного неуклюжий элемент script с type="text/html" — это хитрый прием, позволяющий получить фрагмент HTML, загруженный браузером, без его разбора или рендеринга, поскольку браузеры игнорируют сценарии неизвестного типа. Содержимое скрипта представляет собой шаблон, похожий на Mustache/Handlebars (хотя у Ractive есть некоторые расширения).

Сначала мы пишем код шаблона, предполагая, что у нас есть доступ к массиву навыков. Мы используем директиву усов {{#each}} для определения итерации. Внутри директивы текущий элемент может быть доступен как this . Опять же, мы предполагаем, что переменная skills содержит массив строк, поэтому мы просто визуализируем ее с интерполяционными усами {{this}} .

Хорошо, это HTML. Но как насчет JavaScript? Вот тут-то и происходит «магия», которая поставляет данные в шаблон:

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

Впечатляет, нет? Всего за эти 10 строк кода мы можем:

  1. «Извлечь» данные из «БД».
  2. Создайте новое приложение Ractive.
  3. Скажите ему, чтобы он отображался внутри элемента с помощью .
  4. Скажите ему использовать элемент сценария с чтобы получить шаблон (есть и другие способы сделать это).
  5. Передайте начальные данные (мы увидим, как их изменить во время выполнения) или «область действия», если вы привыкли к терминологии Angular.
  6. Используйте метод keys lodash, чтобы получить имена навыков, которые мы используем в качестве ключей объектов в «БД».

Таким образом, в основном с помощью этого скрипта мы сообщаем фреймворку, что делать, но не как это делать. В шаблоне указано, как это сделать, что лично я нахожу довольно удивительным и естественным.

Надеюсь, вы начинаете понимать идею, так что теперь давайте реализуем что-то более полезное в дополнение к тому, что у нас есть.

Поиск навыков

Страница поиска, конечно же, нуждается в поле поиска. И мы хотели бы, чтобы он предоставлял интерактивную возможность, благодаря которой, когда пользователь вводит текст в поле поиска, список навыков отфильтровывается и включает только те, которые содержат введенную подстроку (с фильтрацией без учета регистра).

Как обычно в Ractive, мы начинаем с определения шаблона (при этом думая, какие новые переменные контекста потребуются и что изменится в отношении управления данными):

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

Не так много изменений, но все же есть чему поучиться.

Во-первых, мы добавили новый <div>, содержащий поле поиска. Совершенно очевидно, что мы хотим связать эти входные данные с некоторой переменной (если только вы не ностальгируете по старым добрым дням супа jQuery). Ractive поддерживает так называемую двустороннюю привязку, что означает, что ваш JS-код может получить значение без необходимости считывать его вручную из DOM. В нашем случае это достигается с помощью интерполяционных усов value="{{ skillFilter }}" . Ractive понимает, что мы хотим привязать эту переменную к атрибуту значения ввода. Таким образом, он наблюдает за вводом для нас и автоматически обновляет переменную. Довольно аккуратно всего с 1 строкой HTML.

Во-вторых, как объяснено в комментарии к фрагменту кода выше, теперь вместо отображения всех навыков мы создадим JS-функцию skills() , которая будет фильтровать список навыков и возвращать только те, которые соответствуют тексту, введенному пользователем:

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

Хотя это чисто и просто реализовать, вам может быть интересно, как это влияет на производительность. Я имею в виду, мы будем вызывать функцию каждый раз? Ну каждый раз что? Ractive достаточно умен, чтобы перерисовывать части шаблона (и вызывать любые функции из них) только при изменении их зависимостей (переменных) (Ractive знает, когда это происходит, благодаря использованию сеттеров).

Между прочим, для тех, кто заинтересован в том, чтобы сделать еще один шаг вперед, есть также более элегантный способ сделать это с помощью вычисляемого свойства, но я оставлю его для вас, чтобы вы могли поиграть с ним самостоятельно, если хотите.

Страница результатов

Теперь, когда у нас есть удобный список навыков с возможностью поиска, давайте перейдем к представлению результатов, где будет отображаться соответствующий список разработчиков.

Переключение на представление навыков и обратно

Очевидно, есть несколько способов, как это можно реализовать. Я выбрал подход с двумя разными представлениями в зависимости от того, был выбран навык или нет. Если это так, мы показываем список подходящих разработчиков; если нет, мы показываем список навыков и окно поиска.

Итак, для начала, когда пользователь выбирает (т. е. щелкает) название навыка, список навыков должен быть скрыт, а название навыка должно отображаться вместо заголовка страницы. И наоборот, в выбранном представлении навыков должен быть способ закрыть это представление и вернуться к списку навыков.

Вот наш первый шаг на этом пути:

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

Хорошо, здесь МНОГО всего происходит.

Во-первых, чтобы реализовать это как два разных представления, я переместил все, что у нас было до сих пор (т. е. представление списка), во что-то, называемое частичным. Партиал — это, по сути, кусок кода шаблона, который мы собираемся включить в другое место (скоро).

Затем мы хотим сделать наши навыки кликабельными, а при нажатии мы хотим перейти к соответствующему представлению навыков. Для этого мы используем что-то, называемое прокси-событиями, с помощью которого мы реагируем на физическое событие (при нажатии, имя понятно Ractive) и проксируем его на логическое событие (выбор-навык, имя — это то, что мы называем). ) передачи аргумента (как вы, наверное, помните, здесь это означает название навыка).

(К вашему сведению, существует альтернативный синтаксис вызовов методов для достижения той же цели.)

Затем мы предполагаем (снова), что у нас будет переменная с именем currentSkill , которая будет иметь имя выбранного навыка (если есть) или будет пустой, если никакие навыки не выбраны. Поэтому мы определяем еще один частичный элемент, который показывает название текущего навыка, а также имеет ссылку «ЗАКРЫТЬ», которая должна отменить выбор навыка.

Для JavaScript основным дополнением является код для подписки на события select-skill и deselect-skill, соответственно обновляющий currentSkillskillFilter ):

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

Список разработчиков для каждого навыка

Подготовив новый вид для навыка, теперь мы можем добавить немного мяса — фактический список разработчиков, который у нас есть для этого списка. Для этого мы расширяем партиал для этого представления следующим образом:

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

Надеюсь, к этому моменту вы поняли, что здесь происходит: мы добавили новый раздел итераций в наш skillView , который перебирает результат новой функции skillDevelopers , которую мы напишем в следующий раз. Для каждого разработчика в массиве (возвращаемом этой функцией skillDevelopers ) мы визуализируем панель и отображаем имя разработчика. Обратите внимание, что я мог бы использовать неявную форму {{name}} здесь, и Ractive найдет правильный атрибут, просматривая цепочку контекста, начиная с текущего контекста (который в нашем случае является объектом разработчика, связанным {{#each}} ), но Я предпочитаю быть откровенным. Более подробная информация о контекстах и ​​ссылках доступна в документации Ractive.

А вот реализация функции 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]; }); }

Расширение записи для каждого разработчика

Теперь, когда у нас есть рабочий список разработчиков, пришло время добавить больше деталей и, конечно же, красивое фото:

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

Здесь нет ничего нового со стороны Ractive, но немного более интенсивное использование функций Bootstrap.

Отображение интерактивного списка навыков разработчика

На данный момент мы добились хорошего прогресса, но одна особенность, которой все еще не хватает, — это другая сторона отношений между разработчиком и разработчиком; а именно, мы хотим отобразить навыки каждого разработчика, и мы хотим, чтобы каждый из этих навыков был кликабельной ссылкой, которая ведет нас к представлению результатов для этого навыка.

Но подождите... Я уверен, что у нас уже есть то же самое в списке умений. Да, на самом деле, мы делаем. Он находится в кликабельном списке навыков, но он исходит из другого массива, чем набор навыков каждого разработчика. Тем не менее, они достаточно похожи, и для меня это явный признак того, что мы должны повторно использовать этот фрагмент HTML. И в этом отношении частичные — наш друг.

(Примечание: Ractive также имеет более продвинутый подход к многократно используемым частям представления, известным как компоненты. Они действительно очень полезны, но для простоты мы не будем их сейчас обсуждать.)

Итак, вот как мы достигаем этого с помощью партиалов (и обратите внимание, кстати, что мы можем добавить эту функциональность, не добавляя ни одной строки кода 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}}

У меня уже есть список навыков, прикрепленный к объекту разработчика, который мы получили из «БД», поэтому я просто немного изменил шаблон: я переместил строку, отображающую метку навыка, в партиал и использовал этот партиал там, где эта строка была изначально.

Затем, когда я перебираю навыки разработчика, я могу повторно использовать этот же новый фрагмент, чтобы отобразить каждый из этих навыков в виде кликабельной ссылки. Кроме того, это также проксирует событие select-skill, если вы помните, передавая то же имя навыка. Это означает, что мы можем включить это где угодно (имея надлежащий контекст), и мы получим кликабельную метку, которая ведет к просмотру навыков!

Последний штрих — предварительный загрузчик

Хорошо, теперь у нас есть базовое функциональное приложение. Он чистый и работает быстро, но загрузка все равно занимает некоторое время. (В нашем случае это частично связано с тем, что мы используем несвязанные, не минимизированные источники, но в реальном приложении могут быть и другие важные причины, такие как загрузка исходных данных).

Итак, в качестве последнего шага я покажу вам изящный трюк, чтобы добавить анимацию предварительной загрузки, которая будет удалена, как только Ractive отобразит наше приложение:

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

Так в чем тут магия? Это на самом деле довольно просто. Я добавил некоторый контент (это анимированный индикатор выполнения Bootstrap, но это может быть анимированный GIF или что-то еще) прямо в наш корневой элемент. Я думаю, что это довольно умно — пока наши скрипты загружаются, пользователь видит индикатор загрузки (поскольку он не имеет никакой зависимости от JavaScript, он может отображаться сразу). Однако, как только приложение Ractive будет инициализировано, Ractive перезапишет содержимое корневого элемента (и, таким образом, удалит анимацию предварительной загрузки) визуализированным шаблоном. Таким образом, мы можем добиться этого эффекта, используя всего лишь кусок статического HTML и 0 строк логики. Я думаю, это довольно круто.

Заключение

Подумайте о том, чего мы достигли здесь и как легко мы это сделали. У нас довольно многофункциональное приложение: оно показывает список навыков, позволяет быстро их искать (и даже поддерживает интерактивное обновление списка навыков по мере того, как пользователь вводит текст в поле поиска), позволяет переходить к определенному навыку и обратно, а также перечисляет разработчиков для каждого выбранного навыка. Кроме того, мы можем щелкнуть любой навык, указанный любым разработчиком, чтобы перейти к списку разработчиков с этим навыком. И все это с менее чем 80 строками HTML и менее чем 40 строками JavaScript. На мой взгляд, это довольно впечатляюще и говорит о мощности, элегантности и простоте Ractive.

Рабочая версия приложения доступна онлайн здесь, а полный исходный код общедоступен и доступен здесь.

Конечно, в этой статье мы только коснулись того, что возможно с фреймворком Ractive. Если вам нравится то, что вы видели до сих пор, я настоятельно рекомендую вам начать работу с 60-секундной установкой Ractive и начать самостоятельно изучать все, что может предложить Ractive.