[Из песочницы] Ractive.js — бриллиантовый век web-разработки

Как утверждает сама команда разработчиков, Ractive.js — это библиотека для разработки динамичных web интерфейсов, благодаря которой в мире web-разработки наступит расцвет: всем выдадут бонусы в 100%, холивары «кто круче» отступят в сторону, а разработчики, которые пишут интерактивные, динамичные сайты наконец то перестанут покрываться сединой и материться.Короче, наступит бриллиантовый век веб-разработки.

Начиная очередной проект, прежде чем начать писать Backbone код (фу-фу-фу), решил применить это чудо в проекте (бриллианты!). А так как погуглив похабрив я понял, что на хабре всего одна статья о Ractive.js, нужно устранить эту несправедливость и заодно написать о том, правда ли нам всем свалится вагон счастья и будет ли вообще кто-то доволен. Ведь пообещать «диамантовый век» — это одно (каждые 4 года из телеков слышим), а сделать — совсем другое.

Под катом рассмотрю, что такое и как работает Ractive.js, и подробно распишу продакшн задачу с полной реализацией и описанием, чем это всё грозит уже всем нам.

Вначале что это за зверьЕсли кратко (на самом деле, очень кратко, но идею уловите, а подробности придут с кодом) и по сути: Ractive.js до ужаса прост и состоит из двух половинок: Темплейты (читай «вьюшка»), в которых вы очень декларативно описываете, как ваша программа\компонент должна выглядеть. Данные — собственно данные, которые нужно представить во вьюшке и то, как на них влияет внешний мир (взаимодействие пользователя и\или сетевых запросов). Соответственно, после того, как вы описали темплейт, данные и куда это все это рендарить (обычно id DOM элемента на страничке), Ractive.js обеспечивает (причем абсолютно бескорыстно и без вашего участия) двухстороннюю связь между этими данными и темплейтом.Т.е., как только данные меняются, тут же реактивненько меняется ваша вьюшка, которая соответствует этим данным, добовляются нужные и удаляются устаревшие DOM елементы. Ну и в обратную сторону: как только пользователь чем-то в ваше приложение потыкал — меняются данные.И так по кругу. И все очень реактивненько.

Вы спросите: «А в чем же радость?»

А радость в том, что вы пишите короткий, понятный, декларативный код без миллионов ивентов (которые как обычно летают взад и вперед, а мы пытаемся их обсервить, биндить и т.д.).А главное — нет никаких манипуляций с DOM! Мы не создаем новые элементы… мы не удаляем их из DOM…мы фактически никогда не ищем какой-то элемент при помощи $(selector) — всё всегда под рукой.Ractive выстраивает паралельный DOM точно так же как это делает React и производит только точечные манипуляции с DOM.Никаких лишних движений, и поэтому работает очень быстро. Кстати чем Ractive лучше\хуже React — тема для отдельной статьи.

Всё просто: поменяли данные — поменялось отображение. Это общая идея библиотечки.

Теперь посмотрим на реализацию, реальный код и подробности как это работает. Но сначала сформируем ТЗ к тому, что мы хотим написать.

Практика Необходимо было написать комменты к блогу. Вы спросите, почему не использовать Disqus или что-то подобное. Суть в том, чтонаш проект занимается образованием в области здорового образа жизни и в публичном блоге мы использовали как раз Disqus.Но в рамках проекта проводятся онлайн-тренинги, и комментарии в них должны быть приватными, так как содержат частную информацию и всякие ценные ответы на вопросы.Поэтому пришлось сделать свой компонент.Итак, требования:

Пользователь должен иметь возможность оставить многострочный текст в виде комментария. Комменты должны работать без перезагрузки страницы (интерактивчик как мы все любим). Комменты должны быть древовидными (можно ответить на другой коммент и создать тем самым ветку). Новый коммент должен появляться с красивенькой анимацией. Пользователи могут удалить свой собственный коммент. Собственно что бы сразу понять что и как мы будем строить вот на ссылка на jsfiddle с конечным результатом.

Templates Ractive.js для описание UI использует популярный язык темлпейтов {{mustache}}. Только они его чуть-чуть подхачили и расширили.Не буду описывать тут mustache, о нем можно почитать здесь кто не знаком.Опишу только особенности, которые внёс Ractive:

Ввели переменную this. В блоке она соответствует данному объекту. К примеру, если вы пишите {{#user}}

this.name
{{/user}} , то если var user = {name:'Вася'} получится
Вася
Если блок — это массив, то this будет равняться элементу массива. А также вы можете выполнять любой js код внутри {{ }}. Так, если var user = { age:15, name:'Ольга' } и темплейт: {{#user}}
this.name
{{/user}} то на выходе получим предсказуемый результат
Ольга
Проксирование DOM Events: если писать в темплейте
, где eventName — это название стандартного DOM события (click, submit и т.д.), то при наступлении события, ractive может подписаться на такой ивент в виде ractive.on ('callbackName', function (e){}); Есть еще отличия, но сейчас не до них.Дальше всё просто: каждый инстанс Ractive имеет проперти data с данными, которые должны быть отображены в темплейте.Он засовывает data в темплейт и строит нужную нам HTML структуру, причём каждому объекту из data соответствует блок html из темплейта.Поэтому при изменении data Ractive точно знает, что нужно добавить, а что удалить из реального DOM, и поэтому работает очень быстро, производя точечные замены в DOM.Также, поскольку каждому кусочку DOM теперь соответствует кусок данных в data, все ивенты, которые проксируются черех on-eventName (к примеру on-click), сопровождаются ссылкой на данные из data как context. К примеру, если у меня есть такой темплейт: {{#user}} <-- здесь this=user -->
{{this.username}}
{{/user}} то обработчик события alert_username может выглядеть так: function (e){ var user = e.context; alert (user.username); } Надеюсь, что на реальном примере станет все понятней.

Далее — наша имплементация темплейта для нашей задачи, но сначала опишем структуру наших данных (комментов) в data:

ractive.data = {'replys':[ { md_text: «Тут текст комента», date:10240912834091,//Веремя комента nix //Автор user:{ username:'Василий Петровичь', image:'http://link-roga-serega-avatar.ru' }, //Массив с ответами replys:[{ md_text: «Тут ну очень интересный комента», date:10240912834091, replys:[…]}, {…}] }, { md_text: «Тут текст другого комента», date:10240912834091,//Веремя комента nix user:{ username:'Василий Петровичь' }, ]}; Сам темплейт с комментариями: {{#top_reply}} {{#if replys.length > 0}} {{#if this.reply_draft}} {{>comment_form}} {{else}} {{/if}} {{/if}} {{/top_reply}}

{{#replys}} {{>comment}} {{/replys}}

{{#bottom_reply}} {{>comment_form}} {{/bottom_reply}}

{{this.user.username}} {{#if user.id === current_user.id}} {{/if}}

{{{marked (md_text)}}}

{{^this.reply_draft}} {{/this.reply_draft}}

{{#if this.reply_draft}} {{>comment_form}} {{/if}}

{{#this.replys}} {{>comment}} {{/this.replys}}

{{current_user.username}}

Данные Теперь опишем, как темплейт связаны с данными.Модель тут очень простая, поэтому долго останавливаться не буду: JS класс Comments с пропертями типа текст, дата публикации, пользователь, а также возможностью коммент сохранить на сервер и удалить с него.Также присутствует метод скачивания коммента с сервера, как и обещал ничего интересного. function Comment (id, md_text, user, domain, date, reply_to) { if (! md_text || ! user || ! domain || ! date) { throw new Error ('md_text, user, domain and date is required'); } this.id = id; this.md_text = md_text; this.user = user; this.date = date; this.reply_to = reply_to? reply_to.id || reply_to: null; this.domain = domain; this.replys = []; }; Comment.prototype.destroy = function () { //ajax запрос на удаление коммента }; Comment.prototype.save = function () { //ajax запрос на сохранение комента };

Comment.fetch = function (domain, options) { //скачиваем все комменты за раз. }; Теперь имплементация Ractive компоненты: var Comments = Ractive.extend ({ //$(selector) Элемента куда Ractive будет рендарить этот компонент el: '#comments', //id tag

Рейтинг@Mail.ru