Что мне стоит DOM построить

в 22:50, , рубрики: innerHTML, javascript, mozilla, Лексический анализатор, метки: , ,

У любого 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

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js