Javascript вставить текст из другого файла
Модификации DOM – это ключ к созданию «живых» страниц.
Здесь мы увидим, как создавать новые элементы «на лету» и изменять уже существующие.
Это был пример HTML. Теперь давайте создадим такой же div , используя JavaScript (предполагаем, что стили в HTML или во внешнем CSS-файле).
Устаревшие методы вставки/удаления
Есть несколько других, более старых, методов вставки и удаления, которые существуют по историческим причинам.
Сейчас уже нет причин их использовать, так как современные методы append , prepend , before , after , remove , replaceWith более гибкие и удобные.
Мы упоминаем о них только потому, что их можно найти во многих старых скриптах:
Добавляет node в конец дочерних элементов parentElem .
Вставляет node перед nextSibling в parentElem .
Чтобы вставить newLi в начало, мы можем сделать вот так:
Заменяет oldChild на node среди дочерних элементов parentElem .
Удаляет node из parentElem (предполагается, что он родитель node ).
Все эти методы возвращают вставленный/удалённый узел. Другими словами, parentElem.appendChild(node) вернёт node . Но обычно возвращаемое значение не используют, просто вызывают метод.
Решение задачи
Для начала подключим на страницу index.html файл со скриптом, который будет называться gettext.js .
В файле index.html внутри элемента поместим элемент с атрибутом src и его значением gettext.js
Логика работы такая:
- Посылаем запрос на сервер.
- Дожидаемся ответа. Ловим содержимое файла.
- Вносим нужные изменения в документ.
Отредактируем файл gettext.js
В первой строке мы создаём анонимную функцию и помещаем её в переменную "inBody". Название переменной описывает решаемую задачу - дословно "вТело". То есть результатом выполнения этой функции будет интеграция содержимого файла text.html внутрь элемента загруженной странице index.html на клиенте (в браузере)
Пятой строкой мы выводим в консоль результат ответа сервера. Она необходима для разработки. Она не обязательна. ВНИМАНИЕ! Содержимое ответа по-умолчанию имеет тип данных - string (строка). Это стандарт клиент-серверного взаимодействия. Все данные передаются по сети в виде "строковых данных". Так всегда происходит - это норма. Если вы точно знаете каким образом строка будет оформлена, тогда вы можете воспользоваться атрибутом ответа responseType и в этом случае содержимое ответа будет одним из:
- пустая строка (по умолчанию),
- arraybuffer
- blob
- document
- json
- text
Восьмая строка инициирует запрос на сервер методом send() и отправляет его.
На десятой строке мы вызываем функцию "inBody"
Пример вставки
- В отличие от тег может быть в любом месте документа, даже в .
- При вставке через документ показывается внутри фрейма. В случае с это не так, по умолчанию документ вообще не показывается.
HTML, загруженный через имеет отдельный DOM документа, но скрипты в нём выполняются в общем контексте страницы.
Файл, загруженный через , обрабатывается, выполняются скрипты, строится DOM документа, но не показывается, а записывается в свойство link.import .
Мы сами решаем, где и когда его вставить.
В примере ниже подключает документ timer.html и, после его загрузки, вызывает функцию show . Эта функция через link.import.querySelector('time') выбирает интересующую часть подгружённого документа и вставляет её в текущий:
Предпосылки. Зачем это нужно?
Главная идея задачи - это создание шаблонов генерации документов силами JavaScript, при помощи которых можно лучше управлять визуальным содержимым сайта.
Каждая отдельная страница сайта перестаёт быть статичной (уже собранной). В результате, мы разделяем потенциальную страницу на части. Например:
- Один документ отвечает за шапку сайта
- Другой за подвал
- Третий за основное содержимое
- Четвёртый за боковые панели
- Пятый за рекламные баннеры
- Шестой за галерею фотографий
- Седьмой за контактную информацию
- и т. п..
Клонирование узлов: cloneNode
Мы могли бы создать функцию и поместить код туда. Альтернатива – клонировать существующий div и изменить текст внутри него (при необходимости).
Иногда, когда у нас есть большой элемент, это может быть быстрее и проще.
- Вызов elem.cloneNode(true) создаёт «глубокий» клон элемента – со всеми атрибутами и дочерними элементами. Если мы вызовем elem.cloneNode(false) , тогда клон будет без дочерних элементов.
Методы вставки
Чтобы наш div появился, нам нужно вставить его где-нибудь в document . Например, в document.body .
Для этого есть метод append , в нашем случае: document.body.append(div) .
Вот полный пример:
Вот методы для различных вариантов вставки:
- node.append(. nodes or strings) – добавляет узлы или строки в конец node ,
- node.prepend(. nodes or strings) – вставляет узлы или строки в начало node ,
- node.before(. nodes or strings) –- вставляет узлы или строки до node ,
- node.after(. nodes or strings) –- вставляет узлы или строки после node ,
- node.replaceWith(. nodes or strings) –- заменяет node заданными узлами или строками.
Вот пример использования этих методов, чтобы добавить новые элементы в список и текст до/после него:
Наглядная иллюстрация того, куда эти методы вставляют:
Итоговый список будет таким:
Эти методы могут вставлять несколько узлов и текстовых фрагментов за один вызов.
Например, здесь вставляется строка и элемент:
Весь текст вставляется как текст.
Поэтому финальный HTML будет:
Другими словами, строки вставляются безопасным способом, как делает это elem.textContent .
Поэтому эти методы могут использоваться только для вставки DOM-узлов или текстовых фрагментов.
А что, если мы хотим вставить HTML именно «как html», со всеми тегами и прочим, как делает это elem.innerHTML ?
DocumentFragment
DocumentFragment является специальным DOM-узлом, который служит обёрткой для передачи списков узлов.
Мы можем добавить к нему другие узлы, но когда мы вставляем его куда-то, он «исчезает», вместо него вставляется его содержимое.
Обратите внимание, что на последней строке с (*) мы добавляем DocumentFragment , но он «исчезает», поэтому структура будет:
DocumentFragment редко используется. Зачем добавлять элементы в специальный вид узла, если вместо этого мы можем вернуть массив узлов? Переписанный пример:
Мы упоминаем DocumentFragment в основном потому, что он используется в некоторых других областях, например, для элемента template, который мы рассмотрим гораздо позже.
Задача
Необходимо на страницу index.html подключить HTML-разметку из файла text.html , но так чтобы файл text.html содержал только HTML-элементы и . То есть мы хотим подгрузить только уникальную информацию на страницу без "лишних" мета-данных.
Также мы хотим сделать эту загрузку в фоне, без перезагрузки страницы index.html . То есть пользователь не увидит в адресной строке браузера другого адреса. Перезагрузки страницы не будет.
Файл text.html имеет разметку:
ВНИМАНИЕ! Запросы к серверу мы будем делать ТОЛЬКО через работающий локально веб-сервер. Ознакомьтесь с протоколом CORS и стандартом Fetch. Локальный запуск файла index.html в браузере не приведёт к работающему результату. Используйте бесплатный продукт "OpenServer" для своих тестов.
insertAdjacentHTML/Text/Element
С этим может помочь другой, довольно универсальный метод: elem.insertAdjacentHTML(where, html) .
Первый параметр – это специальное слово, указывающее, куда по отношению к elem производить вставку. Значение должно быть одним из следующих:
- "beforebegin" – вставить html непосредственно перед elem ,
- "afterbegin" – вставить html в начало elem ,
- "beforeend" – вставить html в конец elem ,
- "afterend" – вставить html непосредственно после elem .
Второй параметр – это HTML-строка, которая будет вставлена именно «как HTML».
Так мы можем добавлять произвольный HTML на страницу.
Мы можем легко заметить сходство между этой и предыдущей картинкой. Точки вставки фактически одинаковые, но этот метод вставляет HTML.
У метода есть два брата:
- elem.insertAdjacentText(where, text) – такой же синтаксис, но строка text вставляется «как текст», вместо HTML,
- elem.insertAdjacentElement(where, elem) – такой же синтаксис, но вставляет элемент elem .
Они существуют, в основном, чтобы унифицировать синтаксис. На практике часто используется только insertAdjacentHTML . Потому что для элементов и текста у нас есть методы append/prepend/before/after – их быстрее написать, и они могут вставлять как узлы, так и текст.
Создание элемента
DOM-узел можно создать двумя методами:
Создаёт новый элемент с заданным тегом:
Создаёт новый текстовый узел с заданным текстом:
Мы создали элемент, но пока он только в переменной. Мы не можем видеть его на странице, поскольку он не является частью документа.
Итого
Методы для создания узлов:
- document.createElement(tag) – создаёт элемент с заданным тегом,
- document.createTextNode(value) – создаёт текстовый узел (редко используется),
- elem.cloneNode(deep) – клонирует элемент, если deep==true , то со всеми дочерними элементами.
Вставка и удаление:
- node.append(. nodes or strings) – вставляет в node в конец,
- node.prepend(. nodes or strings) – вставляет в node в начало,
- node.before(. nodes or strings) – вставляет прямо перед node ,
- node.after(. nodes or strings) – вставляет сразу после node ,
- node.replaceWith(. nodes or strings) – заменяет node .
- node.remove() – удаляет node .
- parent.appendChild(node)
- parent.insertBefore(node, nextSibling)
- parent.removeChild(node)
- parent.replaceChild(newElem, node)
Все эти методы возвращают node .
Если нужно вставить фрагмент HTML, то elem.insertAdjacentHTML(where, html) вставляет в зависимости от where :
- "beforebegin" – вставляет html прямо перед elem ,
- "afterbegin" – вставляет html в elem в начало,
- "beforeend" – вставляет html в elem в конец,
- "afterend" – вставляет html сразу после elem .
Также существуют похожие методы elem.insertAdjacentText и elem.insertAdjacentElement , они вставляют текстовые строки и элементы, но они редко используются.
Чтобы добавить HTML на страницу до завершения её загрузки:
После загрузки страницы такой вызов затирает документ. В основном встречается в старых скриптах.
Перевод статьи «What are HTML Imports and How Do They Work?», Paula Borowska.
Вы когда-нибудь замечали, что включение одной HTML страницы в другую, это какая-то инородная концепция? Это то, что должно быть просто, но не это не часто происходит. Это не невозможно, но трудно. К счастью есть HTML импорт, который позволяет запросто помещать HTML страницы, а также CSS и JavaScript файлы, внутрь других HTML страниц.
Введение в HTML импорт
HTML импорт, это простая для понимания вещь; это способ вставки на страницу других HTML страниц. Вы можете сказать, что в этом нет ничего особенного, так вот есть; раньше вы не могли это так просто сделать.
Интересно то, что HTML это самые простые файлы, но иногда с ними труднее всего работать. Даже PHP файлы имеют возможность включения, почему же HTML этого не может? Благодаря веб-компонентам, мы, теперь, можем включать одни HTML документы в другие. Также, при помощи этого же тега, мы можем подключать CSS и JavaScript. (Жить стало намного лучше.)
Обходные пути
Раньше, одним из обходных путей было подключение при помощи iFrame; это тяжелые HTML элементы, загружаемые отдельным окном внутри текущего документа. Это немного не то, что нам нужно и при этом с ними, не очень то легко взаимодействовать. iFram'ы могут быть удивительно разочаровывающими, когда с ними приходится работать. Следующим вариантом был AJAX, это когда вы загружали страницу при помощи JavaScript и включали её контент. Это, на самом деле, довольно неудобный и утомительный способ.
Начнём
Базовый синтаксис
Прежде чем смотреть примеры, давайте глянем на синтаксис подгрузки файла через тег импорта. Импорт, это новый тип link тега, так что должно быть нетрудно понять следующую строчку:
Такие строки помещаются в шапке, как вы уже привыкли поступать с JavaScript или CSS файлами.
Базовый пример
Чтобы импорт сработал, страницы должны находиться на одном и том же сервере. Начнем с файла index.html. Это простая HTML страница с базовым импортом:
Видите, я не врала о том, как все просто; это так же просто, как загрузка таблицы стилей или JavaScript-файла.
Внутри intro.html
Что же внутри импортированной страницы?
Это просто div с текстом внутри. Не нужно body или head или чего-то ещё.
Вставка импортированного HTML
Чтобы отобразить импортированный HTML, нам нужно написать несколько строчек на JavaScript. Этот код должен находиться в главном HTML-файле, в нашем случае, index.html. Данный код должен находиться в том месте, где мы хотим увидеть импортированный html. В нашем примере после ‘Hello from Designmodo.’
В нашем скрипте мы получаем контент и присваиваем его переменной. Потом мы просто добавляем содержимое переменной в HTML.
Переходим на следующий уровень
Вы когда-нибудь слышали о CSS атрибуте scoped? Атрибут scoped позволяет вам ограничивать действие тега
Если хотите почитать побольше об атрибуте scoped, посмотрите, что говорит W3C.
Это немного похоже на Bootstrap
Bootstrap, это набор отдельных файлов, как bootstrap.css, boostrap.js и тд. Для плагинов, используется jQuery; Bootstrap предоставляет примеры верстки. Он очень гибок и прост в использовании. Суть Bootstrap в том, что вы можете использовать только необходимые для вашего проекта файлы. Большинство людей загружают все файлы сразу, и это тоже нормально. Идея HTML импорта та же, вы подключаете файлы по мере надобности. Эта логика становится популярной, из-за ускорения загрузки и упрощения организации.
Заключение
Благодаря HTML импорту, вы можете выносить HTML, как и CSS или JavaScript, в отдельные файлы. Это, на самом деле, очень круто. Включение HTML-файлов друг в друга не было простым, до появления HTML импорта. Теперь мы можем создавать повторно-используемый контент, подключаемый одной строкой кода. Это очень мощная вещь — и это круто!
Template, Shadow DOM, и Custom Elements позволяют вам строить UI компоненты проще и быстрее. Однако, это не самый эффективный способ загрузки ресурсов HTML, CSS и JavaScript по отдельности.
Для загрузки библиотек типа jQuery UI или Bootstrap требуются отдельные тэги для JavaScript, CSS, и Web шрифтов. Все становится проще при использовании Web Components с несколькими зависимостями.
HTML импорты позволяют загружать ресурсы как совокупность нескольких файлов этого типа.
Предлагаю вам ознакомиться с видео по данной теме.
Использование HTML импортов
Чтобы загрузить HTML файл, добавьте тэг link с import 'ом в параметре rel и href , содержащий путь до нужного файла. К примеру, если вы хотите загрузить файл под названием component.html в index.html , то все должно выглядеть так:
index.html
Вы можете загружать любые ресурсы, включая скрипты, таблицы стилей и шрифты:
component.html
doctype , html , head , body необязательны. HTML импорты автомагически загрузят все указанные элементы, добавят их на страницу и запустят JavaScript, если имеется.
Порядок исполнения
Браузеры обрабатывают контент по порядку. Это означает, что script в начале HTML будет загружен раньше, чем то же самое, но в конце. Учтите, что некоторые браузеры ожидают завершения исполнения скрипта перед тем, как загружать следующие элементы.
Во избежание блокировки тэгом script оставшегося HTML можно использовать атрибуты async / defer (также можно переместить все скрипты в конец страницы). defer указывает на то, что код можно запустить лишь после загрузки HTML. async позволяет браузеру выполнять эти два действия параллельно.
Итак, как же работают импорты?
Скрипт внутри HTML импорта работает как обычный тэг script с атрибутом defer . В примере ниже index.html запустит script1.js и script2.js внутри component.html перед исполнением script3.js .
index.html
component.html
- Загружается component.html из index.html и ожидает исполнения;
- Загружается script1.js в component.html ;
- Загружается script2.js в component.html после script1.js ;
- Загружается script3.js в index.html после script2.js .
За рамками происходящего
Чтобы избежать этого ограничения, используйте CORS (Cross Origin Resource Sharing). Чтобы узнать больше об этой технологии, прочтите эту статью.
Объекты window и document в импортируемых файлах
Ранее я упоминал то, что импортируемые JavaScript будут запущены на странице. К сожалению, такое нельзя сказать об импортируемых HTML файлах. Чтобы такое происходило и с ними, надо дописать немножко скриптов.
Остерегайтесь того, что объект document в импортируемом файле будет ссылаться на страницу оригинала.
Используя написанный ранее код в качестве примера, заставим document в index.html и component.html ссылаться на document в index.html .
Внесем небольшие изменения в наши файлы.
index.html
Для получения document из component.html дополните ваш код с document.currentScript.ownerDocument .
component.html
Если вы используете webcomponents.js , воспользуйтесь document._currentScript вместо document.currentScript . Нижнее подчеркивание в currentScript используется для поддержания браузеров, не способных работать с этим компонентом без использования сего знака.
component.html
Написав вот это в начале вашего скрипта, можно легко получить доступ к document из component.html , даже если браузер не поддерживает HTML импорты.
Вопросы производительности
Один из плюсов использования импортов — возможность самостоятельно распределить нагрузку страницы и порядок обработки импортируемых объектов. Но это еще и означает, что HTML код увеличится. Вообще, есть несколько пунктов для сравнения:
Зависимости
Что делать, если несколько вставляемых документов ссылаются на одну и ту же библиотеку? Например:
Вы загружаете jQuery в обоих документах, из-за чего при импорте этих документов библиотека в конечном документе будет исполнена дважды.
index.html
component1.html
component2.html
Данная проблема крайне легко решается в импортах.
В отличие от тэга script , объекты нашей статьи не загружают повторно один и тот же материал. Смотря на последний пример, достаточно обернуть тэг script HTML импортом, и данный ресурс не будет загружен дважды.
Но есть и другая проблема: теперь файлов для загрузки стало больше. Что делать, если таких будет не два, а гораздо больше?
К счастью, нам на помощь идет инструмент под названием «Vulcanize».
Объединение сетевых запросов
Vulcanize — инструмент объединения нескольких HTML файлов в один, с помощью чего число подключений к сети в целях загрузки необходимых документов сокращается. Вы можете установить его с помощью npm и использовать в командной строке. Также существуют аналоги для grunt и gulp , с помощью чего можно сделать «Vulcanize» частью вашего процесса сборки.
Для объединения файлов index.html используем следующий код:
При исполнении данной команды все зависимости index.html будут соединены в файле vulcanized.html .
Прочитать больше о данном инструменте можно здесь.
Сочетание импортов с Template, Shadow DOM и Custom Elements
Для тех, кто не знает о данных технологиях: С templates определение содержания пользовательского элемента может быть декларативным. С Shadow DOM styles , ID и classes элемента можно использовать немного иначе. С Custom Elements можно создать собственные HTML тэги. Неплохо, не так ли?
Объединение импортов с собственными веб-компонентами получит модульность и возможность многократного использования. Любой сможет их использовать, добавив лишь тэг link .
x-component.html
Обратите внимание, что объект document в x-component.html такой же, как и в index.html . Не нужно писать ничего сложного, все работает само и за вас.
Поддерживаемые браузеры
HTML импорты поддерживаются браузерами Chrome и Opera. Firefox на данный момент отложил добавление данной фичи, так как «у них есть более приоритетные задачи».
Файл index.html обрабатывается силами web-сервера и автоматически загружается в браузер пользователя при обращении к сайту (главной странице).
Файл index.html имеет классическую разметку документа:
Это "пустая" HTML-страница со своим уникальным адресом. На странице визуально нет ничего. Просто белый лист.
Удаление узлов
Для удаления узла есть методы node.remove() .
Если нам нужно переместить элемент в другое место – нет необходимости удалять его со старого.
Все методы вставки автоматически удаляют узлы со старых мест.
Например, давайте поменяем местами элементы:
Результат работы
Мы видим итоговую страницу с нужным нам содержимым. На favicon не обращаем внимания т. к. браузер Chrome вдруг решил его поискать.
Вкладка имеет название "Документ", которое пришло из элемента .
title в разметке title на вкладке
Разметка итогового документа после выполнения запроса к серверу. Браузер "переварил" строковые данные и преобразовал их в HTML-разметку.
В инструментах разработчика на вкладке Network мы видим последовательность загрузки данных для главной страницы сайта
Сперва браузер запросил HTML-документ главной страницы сайта. Статус 200 - ОК. Потом после разбора разметки браузер загрузил файл со скриптом. Статус 200 - ОК. После этого браузер начал синхронно обрабатывать выполнение инструкций файла скрипта. На восьмой строчке выполнения файла gettext.js мы видим обращение к файлу text.html
Статус 200 - ОК означает успешную подачу запроса - запрашиваемые ресурсы имеются на сервере.
В ответе сервера браузер уже понимает пришедшие данные и подсвечивает HTML-синтаксис, указывая на элементы и . То есть браузер уже сам разобрал пришедший тип данных string и подсветил разработчику открывающиеся и закрывающиеся элементы.
Важно обратить внимание, что на подгрузку данных "в фоне" потребовалось некоторое время. В реальных проектах нужно учитывать эту особенность и правильно распределять зависимости последовательностей отдачи содержимого пользователю.
Может оказаться так, что при формировании финансового графика часть данных не успеет прийти вовремя - это исказит трактование данных из отчёта и навредит бизнесу из-за ошибки вычислений. Будьте внимательны! В таких случаях уместно использовать объект Promise .
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Новая спецификация «HTML Imports» описывает, как вставить один документ в другой при помощи HTML-тега .
Несколько слов о «document.write»
Есть ещё один, очень древний метод добавления содержимого на веб-страницу: document.write .
Вызов document.write(html) записывает html на страницу «прямо здесь и сейчас». Строка html может быть динамически сгенерирована, поэтому метод достаточно гибкий. Мы можем использовать JavaScript, чтобы создать полноценную веб-страницу и записать её в документ.
Этот метод пришёл к нам со времён, когда ещё не было ни DOM, ни стандартов… Действительно старые времена. Он всё ещё живёт, потому что есть скрипты, которые используют его.
В современных скриптах он редко встречается из-за следующего важного ограничения:
Вызов document.write работает только во время загрузки страницы.
Если вызвать его позже, то существующее содержимое документа затрётся.
Так что после того, как страница загружена, он уже непригоден к использованию, в отличие от других методов DOM, которые мы рассмотрели выше.
Это его недостаток.
Есть и преимущество. Технически, когда document.write запускается во время чтения HTML браузером, и что-то пишет в документ, то браузер воспринимает это так, как будто это изначально было частью загруженного HTML-документа.
Поэтому он работает невероятно быстро, ведь при этом нет модификации DOM. Метод пишет прямо в текст страницы, пока DOM ещё в процессе создания.
Так что, если нам нужно динамически добавить много текста в HTML, и мы находимся на стадии загрузки, и для нас очень важна скорость, это может помочь. Но на практике эти требования редко сочетаются. И обычно мы можем увидеть этот метод в скриптах просто потому, что они старые.
Зачем?
Мы ведь и так можем вставлять документ в документ, при помощи , зачем нужен ещё какой-то импорт? Что не так с iframe ?
…С iframe всё так. Однако, по своему смыслу iframe – это отдельный документ.
- Для iframe создаётся полностью своё окружение, у него свой объект window и свои переменные.
- Если iframe загружен с другого домена, то взаимодействие с ним возможно только через postMessage .
Это хорошо, когда нужно действительно в одной странице отобразить содержимое другой.
А что, если нужно встроить другой документ как естественную часть текущего? С единым скриптовым пространством, едиными стилями, но при этом – другой документ.
Например, это нужно для подгрузки внешних частей документа (веб-компонент) снаружи. И желательно не иметь проблем с разными доменами: если уж мы действительно хотим подключить HTML с одного домена в страницу на другом – мы должны иметь возможность это сделать без «плясок с бубном».
Иначе говоря, – это аналог , но для подключения полноценных документов, с шаблонами, библиотеками, веб-компонентами и т.п. Всё станет понятнее, когда мы посмотрим детали.
Читайте также: