javascript

Добавляем реактивность в строковые шаблонизаторы

  • пятница, 23 июня 2017 г. в 03:14:41
https://habrahabr.ru/post/331400/
  • Разработка веб-сайтов
  • jQuery
  • JavaScript
  • HTML


Одним из преимуществ строковых шаблонизаторов таких как JUST.js, jqueryTmpl или handlebarsjs перед шаблонизаторами на основе виртуального DOM дерева (VUE.js, angular) это низкий порог вхождения и простота в использовании. Ещё как мне кажется со строковыми шаблонизаторами проще интегрировать плагины для jquery.

Однако возможность реактивного связывания данных модели с шаблоном действительно удобный инструмент, и после того как я пробовал VUE.js и angular мне стало очень не хватать этого в моём любимом шаблонизаторе JUST.JS.

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

Начнём с простого примера


В нём мы обошлись вообще без шаблонизатора для простоты и наглядности кода. В данном примере раз в секунду в переменную присваивается новое значение. И затем justReactive за вас вносит измения в dom дерево страницы.

Библиотека justReactive добавляет следующие методы для Object каждый из которых предназначен для вставки отслеживаемого значения в разные места html кода.

  • justHtml — отображение текста или html кода из переменной без какой либо фильтрации
  • justText — отображение текста из переменной как текста, с преобразованием html сущностей в текст
  • justClass — подставляет класс если значение отслеживаемой переменой не false
  • justNotClass — подставляет класс если значение отслеживаемой переменой false
  • justClassName — подставляет как класс само значение отслеживаемой переменой
  • justAttr — подставляет и обновляет атрибут у элемента

Принцип действия


Следующий вызов:

model.justText('time')

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

Так на пример justText вернёт следующий html-код:

<div id="_justReactive2" style="display: inline;" class="just-watch just-watch-text">1498115282970</div>

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

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

Ещё пример использования


Этот пример основан на предыдущем. Здесь мы добавили отслеживание ещё переменной model.class для изменения класса элемента и переменной model.hide для скрытия ещё одного элемента.

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

var model = {};
model.key1 = 1;

$("#time1").html(model.justText('key1'))
model = {key1:2};

В данном примере значение в dom дереве не будет обновлено так как присваивание в model = {key1:2}; фактически сначала удалило отслеживаемый нами model.key1, а потом создало новый объект model с таким же, но не тем же самым ключом key1.

Циклы и блоки шаблонов


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

Для решения этой задачи мы бы могли вставлять сразу большой блок html кода в какой то из элементов.

Но такое хоть и работает но всё же не очень удобно. Я лично для себя сделал форк шаблонизатора just.js и добавил в него ряд дополнительных возможностей попутно вырезав то что мне казалось в нём лишнем.

Получившийся модифицированый шаблонизатор я назвал just-template

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

<~ this.data.itemslist> 
  <% for(var i in this.data.itemslist){ %>
       <li><%= this.data.itemslist[i].justText('name') %> - <%- this.data.itemslist[i].text %></li>
  <% } %>
<~>

Добавил фильтрацию данных:

<%- text %> - с фильтрацией
<%= text %>  - без фильтрации

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

Финальный пример с массивом и циклами и шаблоном.