У любого javascript-программиста время от времени возникает потребность вставить фрагмент разметки на страницу. Для больших фрагментов используются шаблонизаторы. А что если необходимо много раз вставлять маленькие кусочки? В plain js легко и элегантно этого не сделать. Решение в лоб — использовать innerHTML. Но это ужасное решение! Меня просто воротит когда я вижу это в коде подобное:
el.innerHTML = "<div id='main'>"+hello+"world!</div>";
Другое решение предложила Mozilla — библиотеку html2dom для генерации html путём построения цепочечных вызовов из строки разметки. Это решение достаточно не плохое, однако не решает главную задачу — необходимость просто и понятно описать разметку.
В конце концов я решил написать собственную библиотеку которая решает все нужные задачи — быстрая и безопасная генерация DOM из шаблона с тёплым ламповым синтаксисом.
Библиотека носит название SNC — Simple Node Creator. Она не манипулирует строкой разметки (innerHTML в частности), а имеет свой весьма простой, понятный и во многом знакомый синтаксис. На вход она принимает строку — шаблон, на выходе вполне себе готовый DocumentFragment.
В основе библиотеки лежит лексический анализатор. Вначале весь шаблон разбивается на массив токенов. При этом для токена-разделителя будет сохраняться его символьный код. Это позволит во время перебора массива однозначно его идентифицировать — по типу. В конце мы проходим по этой последовательности токенов и собираем документ.
Синтаксис
Любое описание узла начинается с его имени. Именем должно служить название html тэга. Затем уже мы декораторами добавляем различные сущности к элементу.
.class
— добавить класс.
#id
— добавить идентификатор.
[...]
— позволяет задавать вложенные узлы: div.parent[ span.child ]
;
— разделитель узлов на одном уровне: ul.menu[ li#home; li#abount ]
:attr
— пустой атрибут.
:attr@value
или :attr=value
— один из вариантов передачи значения атрибута. В этом случае на значение накладываются ограничения — он не должен содержать управляющих символов #.[]:%@
. Если имя атрибута начинается с «on», то будет добавлен обработчик события, имя обработчика будет значение value, а тело из второго аргумента. Обработчик будет добавлен стандартными средствами, динамически. А если имя начинается с «jq», то будет навешено jQuery-событие. Имя обработчика можно задать двояко — :onclick@handler
и :onclick@%handler
— оба эти способа несут один и тот же смысл.
%variable
— универсальный способ задания переменных, а также способ передать текстовые данные (html entities передаются корректно). Вы можете написать #%id
и тогда имя атрибута будет взято из второго параметра — карты значений. Это простой объект, где каждому ключу соответствует имя в шаблоне. С недавнего времени он может быть и массивом, значения в этом случае берутся последовательно, по мере обработки шаблона. Такие переменные поддерживаются для всех основных элементов — идентификаторов, классов, атрибутов и их значений.
Существует ещё и третий параметр — он отвечает за то, чтобы не генерировалось исключение, если вы вдруг забыли указать значение переменной. Использовать его не рекомендую. В этом случае вместо пропущенных значений будет подставлено «undefined».
Использование
Вызывайте функцию SNC
, которой передавайте необходимые параметры.
Несколько примеров шаблонов было показано выше. Вот ещё один большой пример:
SNC("div #parent [" +
"i.icon-open;" +
"span.child%txt" +
"] :data-status@%status" +
":onclick@handler" +
":jqcustomevent=jhandler", {
txt:"lorem ipsum",
status:1,
handler:function(e){ console.log("Standart event"); },
jhandler:function(){ console.log("Custom event"); }
});
Планы
Следующим пунктом развития будет добавление циклов. Синтаксис я подсмотрел у Emmet. Будет нечто вроде такого:
SNC("table [ {tr [ { td } * 2 ]} * 8 ]");
Также необходимо перевести readme на английский. Но тут я надеюсь на помощь сообщества.
Реп: github.com/ReklatsMasters/SNC
Автор: ReklatsMasters