Аватар Илларионова Алексея Лого Ilcom.site

Сравнение методов добавления HTML: Template vs JS

Выбор между использованием чистого HTML-тега <template> и использованием переменных JavaScript для хранения шаблона зависит от того, насколько часто меняются данные в шаблоне.

1. Тег <template> в HTML

Этот элемент предназначен для хранения HTML-разметки, которая не отображается при загрузке страницы. Его удобно использовать для многократных вставок (например, карточек товаров). [1]

2. Шаблонные литералы в JavaScript

Если шаблон полностью зависит от данных (динамический контент), его проще создавать прямо в коде JS с помощью обратных кавычек ` и синтаксиса ${}. [3, 4]

Сравнение способов

ОсобенностьТег <template>\J\S Шаблоны (Строки)
Где хранитсяВ HTML-документеВ файле .js
ПроизводительностьВысокая (браузер парсит заранее)Ниже (парсинг строки при вставке)
ЧитаемостьОтличная для сложной версткиУдобна для коротких вставок
ДинамичностьТребует ручного поиска элементовПеременные вставляются напрямую $

Рекомендация: Если у вас большая структура (например, модальное окно), используйте HTML <template>. Если нужно быстро вывести одну-две строки данных — используйте JS шаблоны. [3, 5]

Исключение элементов шаблона из поиска

Элементы внутри тега <template> автоматически исключаются из обычного поиска по DOM.

Это происходит потому, что содержимое шаблона находится не в основном документе, а в специальном фрагменте — DocumentFragment (свойство .content).

Как это работает на практике:

  1. Стандартные методы их «не видят»:
    Методы вроде document.querySelector(), document.querySelectorAll() или document.getElementById() ищут только в «живом» дереве страницы. Тег <template> для них — это просто пустой контейнер.

    __// Если в шаблоне есть <button class="btn">, этот поиск вернет null__  
    const btn = document.querySelector('.btn');  
  2. Как найти элементы внутри шаблона намеренно:
    Если вам всё же нужно что-то изменить в самом шаблоне (например, текст-заглушку) перед клонированием, нужно обращаться напрямую к его свойству .content:

    const temp = document.getElementById('my-template');  
    const btnInTemplate = temp.content.querySelector('.btn'); __// Ищет только ВНУТРИ шаблона__  

Единственный нюанс (на что стоит обратить внимание):

Если вы используете атрибуты выбора по тегам (например, document.getElementsByTagName('div')), вы получите сам элемент <template>, но не те div, которые лежат внутри него.

Итог: Вам не нужно предпринимать никаких специальных действий, чтобы «исключить» шаблон из поиска. Браузер уже сделал это за вас, сделав содержимое шаблона «инертным».

Элементы формы внутри шаблона

Да, абсолютно все элементы, находящиеся внутри <template>, включая поля формы (<input>, <select>, <textarea>), автоматически исключаются из документа.

Вот что это означает на практике:

  1. Они не участвуют в отправке: Если внутри <form> лежит <template> с инпутами, при отправке формы данные из этих инпутов не уйдут на сервер.
  2. Валидация их не видит: Атрибуты required, pattern или minlength внутри шаблона не работают, пока вы не «оживите» их в DOM.
  3. Доступ через **form.elements**: Если вы обращаетесь к форме через JS (document.forms[0].elements), инпуты из шаблона там не появятся.
  4. Автофокус: Атрибут autofocus внутри шаблона не сработает при загрузке страницы.

Почему это удобно для форм?

Это идеальный способ реализации динамических полей (например, кнопка «Добавить ещё один телефон»):

Важный момент: если вы даете элементам внутри шаблона id, они не будут конфликтовать с id на основной странице, пока остаются внутри <template>. Но как только вы клонируете шаблон в документ 5 раз — у вас появится 5 элементов с одинаковыми id, что плохо. В таких случаях лучше использовать классы.

Передача через шаблоны сложных объектов

При динамическом добавлении полей (например, список контактов или товаров) важно, чтобы сервер получил их в виде массива или структурированных данных.

Вот лучший способ сделать это с помощью <template> и индексации имён.

1. Используйте синтаксис массивов в name

Если вы добавите в шаблон name="phones[]", большинство серверных языков (PHP, Python, Node.js) автоматически соберут все значения с таким именем в один массив.

2. Пример реализации (Код)

Этот код при каждом клике создает новую строку с уникальным индексом или просто как элемент массива.

__<!-- Форма -->__  
<form id="user-form" action="/save" method="POST">  
  <div id="fields-container">  
    __<!-- Сюда будем добавлять новые поля -->__  
  </div>  
    
  <button type="button" id="add-btn">Добавить телефон</button>  
  <button type="submit">Отправить</button>  
</form>

__<!-- Шаблон -->__  
<template id="phone-template">  
  <div class="field-group" style="margin-bottom: 10px;">  
    <input type="text" name="phones\[\]" placeholder="Введите номер" required>  
    <button type="button" class="remove-btn">✖</button>  
  </div>  
</template>  
  
<script>  
  const container = document.querySelector('#fields-container');  
  const template = document.querySelector('#phone-template');  
  const addBtn = document.querySelector('#add-btn');  
  
  addBtn.addEventListener('click', () => {  
    // 1. Клонируем содержимое шаблона (true — глубокое клонирование)  
    const clone = template.content.cloneNode(true);  
  
    // 2. Опционально: можно программно изменить name, если нужны индексы (phones\[0\], phones\[1\]...)  
    // Но для простых списков phones\[\] достаточно.  
  
    // 3. Добавляем логику удаления для кнопки внутри клона  
    clone.querySelector('.remove-btn').addEventListener('click', (e) => {  
      e.target.closest('.field-group').remove();  
    });  
  
    // 4. Вставляем в DOM  
    container.appendChild(clone);  
  });  
</script>  

3. Как это увидит сервер?

Когда пользователь нажмет «Отправить», в теле запроса будет:
phones=89001112233&phones=89004445566

Почему это правильно:

  1. Порядок сохранен: Элементы придут на сервер в том же порядке, в котором они расположены в DOM.
  2. Минимум JS: Вам не нужно вручную считать counter++ и подставлять name="phone_1", name="phone_2". Браузер и сервер всё сделают за вас через [].
  3. Гибкость: Удаление любого элемента из середины списка не сломает логику — сервер всё равно получит плотный массив из оставшихся полей.