Шаблонизация через HTMLElement

Шаблонизация через HTMLElement опирается на прямое использование DOM API без промежуточных DSL и без внешних шаблонизаторов. В контексте современных сборщиков, таких как Parcel, этот подход становится особенно устойчивым благодаря предсказуемой работе модулей, быстрой пересборке и минимальному количеству абстракций поверх браузерного API.

Основная идея заключается в том, что UI строится не как строка HTML, а как дерево объектов Node, создаваемое программно. Это исключает этап парсинга HTML-строк и позволяет работать с интерфейсом как с обычной структурой данных.


Базовая модель построения интерфейса через DOM

DOM-элемент создаётся через document.createElement, после чего его свойства и дочерние узлы настраиваются императивно:

const button = document.createElement('button');
button.textContent = 'Сохранить';
button.className = 'primary-button';

document.body.appendChild(button);

Такой подход формирует основу шаблонизации: каждый UI-фрагмент представляется функцией, возвращающей готовый HTMLElement.


Функциональная инкапсуляция шаблонов

Повторно используемые элементы удобно оформлять как функции-фабрики:

function createButton(label) {
  const button = document.createElement('button');
  button.textContent = label;
  button.className = 'button';

  return button;
}

const saveButton = createButton('Сохранить');
const cancelButton = createButton('Отмена');

document.body.append(saveButton, cancelButton);

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


Композиция DOM-узлов

Шаблонизация через HTMLElement становится масштабируемой при композиции:

function createCard(title, content) {
  const wrapper = document.createElement('div');
  wrapper.className = 'card';

  const header = document.createElement('h3');
  header.textContent = title;

  const body = document.createElement('p');
  body.textContent = content;

  wrapper.append(header, body);

  return wrapper;
}

document.body.appendChild(
  createCard('Заголовок', 'Содержимое блока')
);

Композиционный подход заменяет необходимость строковых шаблонов и позволяет избегать проблем с экранированием HTML.


Связь с системой модулей Parcel

В рамках Parcel каждый компонент, реализованный через HTMLElement, обычно оформляется как отдельный ES-модуль:

// button.js
export function createButton(label) {
  const button = document.createElement('button');
  button.textContent = label;
  return button;
}
// main.js
import { createButton } from './button.js';

document.body.appendChild(createButton('OK'));

Parcel автоматически отслеживает зависимости между модулями и перестраивает только изменённые части, что делает подход с DOM-шаблонами особенно эффективным в разработке UI.


Использование template literals в связке с HTMLElement

Хотя основа шаблонизации — DOM API, template literals могут использоваться как вспомогательный инструмент для генерации текстовых узлов:

function createUser(name, age) {
  const container = document.createElement('div');

  container.innerHTML = `
    <span class="name">${name}</span>
    <span class="age">${age}</span>
  `;

  return container;
}

Однако такой подход снижает контроль над структурой DOM и требует осторожного обращения с динамическими данными.

Альтернативой является полное исключение innerHTML:

function createUser(name, age) {
  const container = document.createElement('div');

  const nameEl = document.createElement('span');
  nameEl.textContent = name;

  const ageEl = document.createElement('span');
  ageEl.textContent = String(age);

  container.append(nameEl, ageEl);

  return container;
}

Управление состоянием через пересоздание узлов

Шаблонизация на HTMLElement часто реализует модель «перерисовки через пересоздание»:

function renderCounter(value) {
  const root = document.createElement('div');

  const label = document.createElement('span');
  label.textContent = `Значение: ${value}`;

  root.append(label);

  return root;
}

let state = 0;

function update() {
  const newView = renderCounter(state);
  app.replaceChildren(newView);
}

Здесь состояние не привязано к DOM напрямую, а DOM строится заново при изменении данных.


Частичное обновление DOM

Более оптимизированный вариант предполагает обновление только изменённых узлов:

const label = document.createElement('span');
label.textContent = '0';

document.body.appendChild(label);

function increment() {
  state++;
  label.textContent = String(state);
}

Такой подход уменьшает количество операций пересборки DOM и повышает производительность.


Стилизация в рамках HTMLElement-шаблонов

Стили могут применяться напрямую через свойства элемента:

const box = document.createElement('div');
box.style.width = '100px';
box.style.height = '100px';
box.style.backgroundColor = 'tomato';

Либо через классы:

box.classList.add('box', 'box--active');

Parcel при этом позволяет импортировать CSS прямо в JavaScript-модули:

import './styles.css';

Это обеспечивает автоматическую сборку стилей вместе с DOM-структурой.


Компонентный стиль организации

Шаблонизация через HTMLElement естественно приводит к компонентной архитектуре:

export function createModal(title, content) {
  const overlay = document.createElement('div');
  overlay.className = 'overlay';

  const modal = document.createElement('div');
  modal.className = 'modal';

  const header = document.createElement('h2');
  header.textContent = title;

  const body = document.createElement('div');
  body.textContent = content;

  modal.append(header, body);
  overlay.append(modal);

  return overlay;
}

Компонент становится чистой функцией, возвращающей DOM-структуру без скрытых зависимостей.


Интеграция событий в шаблоны

События привязываются напрямую к элементам:

function createCounter() {
  const button = document.createElement('button');
  const label = document.createElement('span');

  let value = 0;

  button.textContent = 'Увеличить';
  label.textContent = String(value);

  button.addEventListener('click', () => {
    value++;
    label.textContent = String(value);
  });

  const wrapper = document.createElement('div');
  wrapper.append(button, label);

  return wrapper;
}

Такой стиль исключает необходимость декларативных обработчиков и сохраняет полный контроль над поведением.


Производственные ограничения и оптимизация

При использовании HTMLElement-шаблонов важно учитывать стоимость операций:

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

Оптимизация достигается через:

  • кеширование узлов
  • минимизацию перерисовок
  • разделение статической и динамической части интерфейса
  • локальные обновления текстовых узлов

Архитектурная устойчивость подхода

Шаблонизация через HTMLElement формирует модель, в которой:

  • отсутствует зависимость от сторонних шаблонизаторов
  • структура UI полностью прозрачна
  • поведение контролируется стандартным API браузера
  • сборщик модулей обеспечивает связность и масштабирование

В связке с Parcel такой подход становится предсказуемым инструментом построения интерфейсов без дополнительного слоя абстракции над DOM.