Anexando string HTML ao DOM

121

Como anexar esta string HTML

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

para o DIV com o ID 'test'que está no DOM?

(Btw div.innerHTML += str;não é aceitável.)

Šime Vidas
fonte

Respostas:

242

Use insertAdjacentHTMLse estiver disponível, caso contrário, use algum tipo de reserva. insertAdjacentHTML é compatível com todos os navegadores atuais .

div.insertAdjacentHTML( 'beforeend', str );

Demonstração ao vivo: http://jsfiddle.net/euQ5n/

Neil
fonte
1
@alex É o mesmo conceito: analisar uma string HTML e colocá-la no DOM. Mas a funcionalidade é diferente - innerHTMLcoloca a string no elemento (substituindo todos os filhos), enquanto insertAdjacentHTMLcoloca (1) antes do elemento, (2) depois do elemento, (3) dentro do elemento antes do primeiro filho ou (4) dentro do elemento após o último filho.
Šime Vidas
3
@alex insertAdjacentHTMLé mais rápido do que anexar a innerHTML, porque insertAdjacentHTMLnão serializa e reanalisa os filhos existentes do elemento.
hsivonen
2
Além disso, insertAdjacentHTMLmantém os valores dos elementos alterados do formulário, ao passo que anexar para innerHTMLreconstruir o elemento e perder todo o contexto do formulário.
Brandon Gano,
20

Isso é aceitável?

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

jsFiddle .

Mas , a resposta de Neil é uma solução melhor.

alex
fonte
1
@ Šime Trabalhar com a API DOM sempre parece um hack: P Você prefere desserializar a string sem innerHTML ?
alex
Bem, sim, se houver outra maneira de utilizar o analisador HTML do navegador, eu adoraria saber ...
Šime Vidas
1
@ Šime - Acho que há apenas duas maneiras de utilizar o analisador HTML do navegador, innerHTML e document.write. E se você acha que o innerHTML é um hack ...
Alohci,
@Alohci Não é outra forma: insertAdjacentHTML.
Šime Vidas
1
@ Šime -Obrigado. Encontrei a versão WHATWG. Está na especificação de análise e serialização do DOM . Isso indica que, além de innerHTML e insertAdjacentHTML, há outerHTML e, eu acho, createContextualFragment.
Alohci
16

atuação

AppendChild(E) é mais de 2x mais rápido do que outras soluções no Chrome e Safari, insertAdjacentHTML(F) é mais rápido no Firefox. O innerHTML=(B) (não confunda com +=(A)) é a segunda solução rápida em todos os navegadores e é muito mais prático do que E e F.

Detalhes

Ambiente de configuração (10/07/2019) MacOs High Sierra 10.13.4 no Chrome 75.0.3770 (64 bits), Safari 11.1.0 (13604.5.6), Firefox 67.0.0 (64 bits)

insira a descrição da imagem aqui

  • no Chrome E (140k operações por segundo) é mais rápido, B (47k) e F (46k) são o segundo, A (332) é o mais lento
  • no firefox F (94k) é mais rápido, então B (80k), D (73k), E (64k), C (21k) mais lento é A (466)
  • no Safari E (207k) é mais rápido, então B (89k), F (88k), D (83k), C (25k), o mais lento é A (509)

Você pode reproduzir o teste em sua máquina aqui

Kamil Kiełczewski
fonte
12

A ideia é usar innerHTMLem um elemento intermediário e, em seguida, mover todos os seus nós filhos para onde você realmente os deseja 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);
}

Isso evita apagar qualquer manipulador de eventos, div#testmas ainda permite que você anexe uma string de HTML.

Chris Calo
fonte
3

O jeito certo é usar insertAdjacentHTML. No Firefox anterior ao 8, você pode voltar a usar Range.createContextualFragmentse strnão contiver scripttags.

Se o seu strcontém scripttags, você precisa remover os scriptelementos do fragmento retornado por createContextualFragmentantes de inserir o fragmento. Caso contrário, os scripts serão executados. ( insertAdjacentHTMLmarca os scripts como não executáveis.)

hsivonen
fonte
Obrigado por mencionar createContextualFragment . Eu estava procurando uma maneira de fazer alguns inclusões de html com scripts executados apenas se o usuário concordar em definir um cookie.
schliflo
3

Hack rápido :


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

Casos de uso :

1: Salve como arquivo .html e execute em chrome ou firefox ou edge. (IE não funciona)

2: Use em http://js.do

Em ação: http://js.do/HeavyMetalCookies/quick_hack

Dividido com comentários:

<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>

Razão pela qual postei:

JS.do tem dois itens obrigatórios:

  1. Sem autocomplete
  2. Monitor vertical amigável

Mas não mostra mensagens console.log. Vim aqui em busca de uma solução rápida. Eu só quero ver os resultados de algumas linhas de código do scratchpad, as outras soluções dão muito trabalho.

JMI MADISON
fonte
1

Por que isso não é aceitável?

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

seria a maneira clássica de fazer isso.

Nick Brunt
fonte
4
Isso mataria os manipuladores de eventos anexados ao #testembora. Isso geralmente não é desejável.
alex de
É interessante que faça isso. Não parece muito lógico.
Nick Brunt,
2
Acho que é lógico se você pensar em serializar o HTML em uma string e, em seguida, definir o HTML de volta.
alex
Acho que o JavaScript teria que ser executado novamente para redefinir o manipulador de eventos. Justo.
Nick Brunt,
1
@Nick Você não deseja stringificar (serializar) uma parte do DOM apenas para que possa concatená-la com outra string e, em seguida, analisar tudo de volta para o DOM. Como alex disse, a serialização não registra manipuladores de eventos vinculados (entre outras coisas). Mesmo que a serialização pudesse capturar tudo, você ainda não gostaria de fazer isso.
Šime Vidas
0

Isso pode resolver

 document.getElementById("list-input-email").insertAdjacentHTML('beforeend', '<div class=""><input type="text" name="" value="" class="" /></div>');
Rafael Senne
fonte
3
Bem-vindo ao Stack overflow. Explique seu código como parte de uma resposta para fornecer algum contexto, em vez de apenas colar uma única linha longa de código. Embora você o entenda, outros podem não entender o que ele está fazendo.
loan.burger
0

InnerHTML limpa todos os dados como eventos para nós existentes

anexar filho com firstChild adiciona apenas o primeiro filho a innerHTML. Por exemplo, se tivermos que acrescentar:

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

apenas text1 irá aparecer

Que tal isso:

adiciona tag especial a innerHTML anexando filho e, em seguida, edita outerHTML excluindo a tag que criamos. Não sei o quão inteligente é, mas funciona para mim ou você pode alterar outerHTML para innerHTML para que não precise usar a função substituir

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>

Łukasz Szpak
fonte
0

Mais curto - 18 caracteres (não confunda +=(menção por OP) com =mais detalhes aqui )

test.innerHTML=str

Kamil Kiełczewski
fonte