Добавление строки HTML в DOM

121

Как добавить эту HTML-строку

var str = '<p>Just some <span>text</span> here</p>';

в DIV с идентификатором, 'test'который находится в DOM?

(Кстати, div.innerHTML += str;это не приемлемо.)

Шиме Видас
источник

Ответы:

243

Используйте, insertAdjacentHTMLесли он доступен, в противном случае используйте какой-то запасной вариант. insertAdjacentHTML поддерживается во всех текущих браузерах .

div.insertAdjacentHTML( 'beforeend', str );

Живая демонстрация: http://jsfiddle.net/euQ5n/

Нил
источник
1
@alex Это та же концепция: парсинг HTML-строки и помещение ее в DOM. Но функциональность другая - innerHTMLпомещает строку в элемент (заменяя всех дочерних элементов), тогда как insertAdjacentHTMLпомещает ее (1) перед элементом, (2) после элемента, (3) внутри элемента перед первым дочерним элементом или (4) внутри элемента после последнего дочернего элемента.
Шиме Видас,
3
@alex insertAdjacentHTMLбыстрее, чем добавление к innerHTML, потому insertAdjacentHTMLчто не сериализует и не повторно анализирует существующие дочерние элементы элемента.
hsivonen
2
Кроме того, insertAdjacentHTMLсохраняет значения измененных элементов формы, тогда как добавление к innerHTMLперестраивает элемент и теряет весь контекст формы.
Брэндон Гано,
20

Это приемлемо?

var child = document.createElement('div');
child.innerHTML = str;
child = child.firstChild;
document.getElementById('test').appendChild(child);

jsFiddle .

Но , ответ Нила является лучшим решением.

Алекс
источник
1
@ Šime Работа с DOM API всегда кажется хакерской: P Вы бы предпочли десериализовать строку без нее innerHTML?
Alex
Что ж, да, если есть другой способ использовать анализатор HTML в браузере, я хотел бы знать ...
Шиме Видас
1
@ Šime - Я думаю, что есть только два способа использовать HTML-парсер браузера, innerHTML и document.write. И если вы думаете, что innerHTML - это взлом ...
Алохи
@Alohci Там является еще один способ: insertAdjacentHTML.
Шиме Видас,
1
@ Šime -Спасибо. Нашел версию WHATWG. Это находится в спецификации DOM Parsing and Serialization . Это указывает на то, что, помимо innerHTML и insertAdjacentHTML, есть outerHTML и, я думаю, createContextualFragment.
Alohci
16

Производительность

AppendChild(E) более чем в 2 раза быстрее, чем другие решения для Chrome и Safari, insertAdjacentHTML(F) является самым быстрым в firefox. innerHTML=(B) (не путать с +=(А)) является вторым быстрым решением во всех браузерах , и это гораздо удобнее , чем Е и F.

подробности

Настройка среды (2019.07.10) MacOs High Sierra 10.13.4 в Chrome 75.0.3770 (64-разрядная версия), Safari 11.1.0 (13604.5.6), Firefox 67.0.0 (64-разрядная версия)

введите описание изображения здесь

  • в Chrome E (140 тыс. операций в секунду) - самый быстрый, B (47k) и F (46k) - второй, A (332) - самый медленный
  • в firefox F (94k) самый быстрый, затем B (80k), D (73k), E (64k), C (21k) самый медленный - A (466)
  • в Safari E (207k) самый быстрый, затем B (89k), F (88k), D (83k), C (25k), самый медленный - A (509)

Вы можете воспроизвести тест на своей машине здесь

Камил Келчевски
источник
12

Идея состоит в том, чтобы использовать innerHTMLпромежуточный элемент, а затем переместить все его дочерние узлы туда, где они действительно нужны appendChild.

var target = document.getElementById('test');
var str = '<p>Just some <span>text</span> here</p>';

var temp = document.createElement('div');
temp.innerHTML = str;
while (temp.firstChild) {
  target.appendChild(temp.firstChild);
}

Это позволяет избежать уничтожения любых обработчиков событий, div#testно по-прежнему позволяет добавлять строку HTML.

Крис Кало
источник
3

Правильный способ - использовать insertAdjacentHTML. В Firefox ранее 8 вы можете вернуться к использованию, Range.createContextualFragmentесли ваш тег strне содержит scriptтегов.

Если у вас strесть scriptтеги, вам необходимо удалить scriptэлементы из фрагмента, возвращаемого createContextualFragmentперед вставкой фрагмента. В противном случае скрипты запустятся. ( insertAdjacentHTMLотмечает скрипты как невыполнимые.)

hsivonen
источник
Спасибо за упоминание createContextualFragment . Я искал способ сделать некоторые html-включения со сценариями, запускаемыми только в том случае, если пользователь соглашается установить cookie.
Schliflo
3

Быстрый взлом :


<script>
document.children[0].innerHTML="<h1>QUICK_HACK</h1>";
</script>

Случаи использования :

1: Сохраните как файл .html и запустите в Chrome, Firefox или Edge. (IE не работает)

2: использовать в http://js.do

В действии: http://js.do/HeavyMetalCookies/quick_hack

Разбитые с комментариями:

<script>

//: The message "QUICK_HACK" 
//: wrapped in a header #1 tag.
var text = "<h1>QUICK_HACK</h1>";

//: It's a quick hack, so I don't
//: care where it goes on the document,
//: just as long as I can see it.
//: Since I am doing this quick hack in
//: an empty file or scratchpad, 
//: it should be visible.
var child = document.children[0];

//: Set the html content of your child
//: to the message you want to see on screen.
child.innerHTML = text;

</script>

Причина, по которой я опубликовал:

У JS.do есть два обязательных элемента:

  1. Без автозаполнения
  2. Вертикальный монитор дружественный

Но не показывает сообщения console.log. Пришел сюда в поисках быстрого решения. Я просто хочу увидеть результаты нескольких строк кода блокнота, другие решения требуют слишком много работы.

JMI MADISON
источник
1

Почему это неприемлемо?

document.getElementById('test').innerHTML += str

было бы учебным способом сделать это.

Ник Брант
источник
4
Однако это убило бы обработчики событий, прикрепленные к #test. Обычно это нежелательно.
Alex
Интересно, что он это делает. На самом деле это не кажется логичным.
Ник Брант,
2
Думаю, это логично, если вы подумаете о сериализации HTML в строку, а затем вернете HTML обратно.
Alex
Я предполагаю, что для сброса обработчика событий придется снова запустить JavaScript. Справедливо.
Ник Брант,
1
@Nick Вы не хотите структурировать (сериализовать) часть DOM только для того, чтобы вы могли объединить ее с другой строкой, а затем проанализировать все это обратно в DOM. Как сказал Алексей, сериализация не будет записывать связанные обработчики событий (среди прочего). Даже если бы сериализация могла захватить все, вы все равно не захотели бы этого делать.
Шиме Видас,
0

Это может решить

 document.getElementById("list-input-email").insertAdjacentHTML('beforeend', '<div class=""><input type="text" name="" value="" class="" /></div>');
Рафаэль Сенне
источник
3
Добро пожаловать в Stack overflow. Пожалуйста, объясните свой код как часть ответа, чтобы предоставить некоторый контекст, а не просто вставлять длинную единственную строку кода. Хотя вы это понимаете, другие могут не понять, что он делает.
credit.burger 07
0

InnerHTML очищает все данные, такие как событие, для существующих узлов

append child с firstChild добавляет только первого ребенка в innerHTML. Например, если нам нужно добавить:

 <p>text1</p><p>text2</p>

будет отображаться только text1

Как насчет этого:

добавляет специальный тег в innerHTML, добавляя дочерний элемент, а затем редактирует внешний HTML, удаляя созданный нами тег. Не знаю, насколько это умно, но у меня это работает, или вы можете изменить externalHTML на innerHTML, чтобы не использовать замену функции

function append(element, str)
{

  var child = document.createElement('someshittyuniquetag');
		
  child.innerHTML = str;

  element.appendChild(child);

  child.outerHTML = child.outerHTML.replace(/<\/?someshittyuniquetag>/, '');

// or Even child.outerHTML = child.innerHTML


  
}
<div id="testit">
This text is inside the div
<button onclick="append(document.getElementById('testit'), '<button>dadasasdas</button>')">To div</button>
<button onclick="append(this, 'some text')">to this</button>
</div>

Лукаш Шпак
источник