Como inserir um elemento após outro elemento no JavaScript sem usar uma biblioteca?

757

Existe insertBefore()em JavaScript, mas como posso inserir um elemento após outro sem usar o jQuery ou outra biblioteca?

Xah Lee
fonte
4
se você precisar do caso específico do último nó filho - stackoverflow.com/questions/5173545/…
2
@AlanLarimer isso é ótimo. obrigado. você sabe quando o insertAdjacentElement foi introduzido?
Xah Lee 21/09
1
Segundo o MDN, ele é suportado no IE8 e no Firefox 48 (08 de agosto de 2016). Siga a trilha: bugzilla.mozilla.org/show_bug.cgi?id=811259 -> w3.org/Bugs/Public/show_bug.cgi?id=19962 (14 de março de 2016)
Alan Larimer

Respostas:

1276
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);

Onde referenceNodeestá o nó que você deseja colocar newNodedepois. Se referenceNodeé o último filho dentro de seu elemento pai, tudo bem, porque referenceNode.nextSiblingserá nulle insertBeforelida com esse caso, adicionando ao final da lista.

Assim:

function insertAfter(newNode, referenceNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

Você pode testá-lo usando o seguinte snippet:

function insertAfter(referenceNode, newNode) {
  referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

var el = document.createElement("span");
el.innerHTML = "test";
var div = document.getElementById("foo");
insertAfter(div, el);
<div id="foo">Hello</div>

karim79
fonte
8
Obrigado por uma ótima resposta, mas não é confuso alternar referenceNode e newNode na lista de argumentos? Por que não cumprir a sintaxe insertBefore?
GijsjanB
9
Esse trecho de código não manipula se o referenceNode é o último filho, no qual deve anexarChild.
Brad Vogel
72
De acordo com o MDN se o elemento é o último (e assim nextSibling é null) a newNode será anexado como esperado
electroCutie
9
referenceNode.nextElementSibling é uma opção melhor para ser usado
Bhumi Singhal
8
@BhumiSinghal: Errado. insertBefore()trabalha com nós de texto. Por que você quer insertAfter()ser diferente? Você deve criar um par separado de funções nomeadas insertBeforeElement()e insertAfterElement()para isso.
7vujy0f0hy
116

O JavaScript simples seria o seguinte:

Anexar antes:

element.parentNode.insertBefore(newElement, element);

Anexar após:

element.parentNode.insertBefore(newElement, element.nextSibling);

Mas, jogue alguns protótipos para facilitar o uso

Ao criar os seguintes protótipos, você poderá chamar essas funções diretamente dos elementos recém-criados.

  • newElement.appendBefore(element);

  • newElement.appendAfter(element);

.appendBefore (elemento) Protótipo

Element.prototype.appendBefore = function (element) {
  element.parentNode.insertBefore(this, element);
},false;

Protótipo .appendAfter (elemento)

Element.prototype.appendAfter = function (element) {
  element.parentNode.insertBefore(this, element.nextSibling);
},false;

E, para ver tudo em ação, execute o seguinte snippet de código

Execute-o no JSFiddle

Armando
fonte
4
Os nomes das funções de extensão são enganosos. Ele acha que deveria ser chamado appendMeBefore e appendMeAfter. Eu pensei que era usado como o método appendChild () , por exemplo existingElement.appendAfter(newElement);. Veja o que quero dizer neste jsfiddle atualizado .
Stomtech 25/05
2
Anexar Após o trabalho, porque se element.nextSibling não tiver um próximo irmão, nextSibling será NULL e, em seguida, será acrescentado no final.
111319 Stefan Steiger
45

insertAdjacentHTML + outerHTML

elementBefore.insertAdjacentHTML('afterEnd', elementAfter.outerHTML)

De cabeça para baixo:

  • SECADOR: você não precisa armazenar o nó anterior em uma variável e usá-lo duas vezes. Se você renomear a variável, em menos ocorrência para modificar.
  • golfs melhor que o insertBefore(quebra mesmo se o nome da variável do nó existente tiver 3 caracteres)

Desvantagens:

  • menor suporte ao navegador desde a versão mais recente: https://caniuse.com/#feat=insert-adjacent
  • perderá propriedades do elemento, como eventos, porque outerHTMLconverte o elemento em uma sequência. Precisamos disso porque insertAdjacentHTMLadiciona conteúdo de strings em vez de elementos.
Ciro Santilli adicionou uma nova foto
fonte
12
Se você já tem o elemento construído, você pode usar.insertAdjacentElement()
GetFree 13/18
6
A partir de 2018, navegador de apoio parece muito sólidas: caniuse.com/#feat=insert-adjacent
madannes
Esta foi uma boa solução, sugiro eveyone ler este xahlee.info/js/js_insert_after.html
Mehregan Rahmani
37

Uma rápida pesquisa no Google revela esse script

// create function, it expects 2 values.
function insertAfter(newElement,targetElement) {
    // target is what you want it to go after. Look for this elements parent.
    var parent = targetElement.parentNode;

    // if the parents lastchild is the targetElement...
    if (parent.lastChild == targetElement) {
        // add the newElement after the target element.
        parent.appendChild(newElement);
    } else {
        // else the target has siblings, insert the new element between the target and it's next sibling.
        parent.insertBefore(newElement, targetElement.nextSibling);
    }
}
James Long
fonte
29
Para quem se deparar com esse script, não recomendo usá-lo. Ele tenta resolver problemas que a solução nativa do @ karim79 já resolve. Seu script é mais rápido e mais eficiente - eu recomendo fortemente o uso desse script em vez deste.
James Longo
10
Como regra geral em JavaScript, o navegador pode executar uma tarefa mais rapidamente do que qualquer coisa que você possa escrever. Embora as duas soluções sejam funcionalmente iguais, minha solução JavaScript precisa ser lida e entendida pelo navegador antes de poder ser usada e requer uma verificação adicional toda vez que é executada. A solução oferecida por karim79 fará tudo isso internamente, salvando essas etapas. A diferença será trivial na melhor das hipóteses, mas sua solução é a melhor.
James Longo
3
Em outras palavras, está tentando resolver um problema que não existe. Não há nada de intrinsecamente errado sobre o cheque extra, mas acho que ele não está propagando a melhor compreensão destes métodos
1j01
3
Bastante. Estou deixando o script aqui porque é o tipo de coisa que eu costumava escrever, mas a resposta aceita é a melhor, mostra uma melhor compreensão dos métodos e é mais rápida. Não há nenhuma razão usar esta resposta em vez - eu não sou mesmo certo porque ele ainda fica upvotes
James longas
3
Se targetElement é o último elemento entre seus irmãos, ele targetElement.nextSiblingretornará null. Quando node.insertBeforeé chamado com nullo segundo argumento, ele adiciona o nó no final da coleção. Em outras palavras, o if(parent.lastchild == targetElement) {ramo é supérfluo, porque parent.insertBefore(newElement, targetElement.nextSibling);lidará adequadamente com todos os casos, mesmo que pareça de outra forma à primeira vista. Muitos já apontaram isso em outros comentários.
Rolf
26

Embora insertBefore()(consulte MDN ) seja ótimo e faça referência à maioria das respostas aqui. Para maior flexibilidade e para ser um pouco mais explícito, você pode usar:

insertAdjacentElement()(consulte MDN ) Permite fazer referência a qualquer elemento e inserir o elemento a ser movido exatamente para onde você deseja:

<!-- refElem.insertAdjacentElement('beforebegin', moveMeElem); -->
<p id="refElem">
    <!-- refElem.insertAdjacentElement('afterbegin', moveMeElem); -->
    ... content ...
    <!-- refElem.insertAdjacentElement('beforeend', moveMeElem); -->
</p>
<!-- refElem.insertAdjacentElement('afterend', moveMeElem); -->

Outros a serem considerados para casos de uso semelhantes: insertAdjacentHTML()einsertAdjacentText()

Referências:

https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML https: // developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentText

um pouco menos
fonte
Deveria realmente dar amor a esta resposta, é a abordagem moderna para a década de 2020 que está se aproximando rapidamente.
serraosays 28/10/19
1
Como é que esta resposta é tão profunda? Devo recompensar alguns pontos para chamar mais atenção.
Qwerty
16

O método node.after( doc ) insere um nó após outro nó.

Para dois nós DOM node1e node2,

node1.after(node2)insere node2depois node1.

Esse método não está disponível em navegadores mais antigos; portanto, geralmente é necessário um polyfill.

golopot
fonte
Isso leva um pouco de trabalho manual a ser implementado como uma inserção funcional. Porém, infelizmente, acho que isso não funcionaria corretamente.
Senhor SirCode
6

Solução 2018 (más práticas, consulte 2020)

Eu sei que essa pergunta é antiga, mas para qualquer usuário futuro, aqui está um protótipo modificado, este é apenas um micro-preenchimento para a função .insertAfter que não existe, esse protótipo adiciona diretamente uma nova função baseElement.insertAfter(element);ao protótipo Element:

Element.prototype.insertAfter = function(new) {
    this.parentNode.insertBefore(new, this.nextSibling);
}

Depois de colocar o polyfill em uma biblioteca, essência ou apenas no seu código (ou em qualquer outro lugar onde ele possa ser referenciado), basta escrever document.getElementById('foo').insertAfter(document.createElement('bar'));


Solução de 2019 (Feio, vá para 2020)

Nova edição: você não deve usar protótipos. Eles substituem a base de código padrão e não são muito eficientes ou seguros e podem causar erros de compatibilidade, mas se for para projetos não comerciais, isso não deve importar. Se você deseja uma função segura para uso comercial, basta usar uma função padrão. não é bonito, mas funciona:

function insertAfter(el, newEl) {
    el.parentNode.insertBefore(newEl, this.nextSibling);
}

// use

const el = document.body || document.querySelector("body");
// the || means "this OR that"

el.insertBefore(document.createElement("div"), el.nextSibling);
// Insert Before

insertAfter(el, document.createElement("div"));
// Insert After 


Solução 2020

Padrões da Web atuais para ChildNode: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode

Está atualmente nos padrões vivos e é SEGURO.

Para navegadores não suportados, use este Polyfill: https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

Alguém mencionou que o Polyfill usa Protos, quando eu disse que eram más práticas. Eles são, especialmente quando usados ​​incorretamente, como minha solução para 2018. No entanto, esse polyfill está na documentação do MDN e usa um tipo de inicialização e execução mais segura. Além disso, é para suporte a navegadores mais antigos, nos dias em que a substituição de protótipo não era tão ruim.

Como usar a solução 2020:

const el = document.querySelector(".class");

// Create New Element
const newEl = document.createElement("div");
newEl.id = "foo";

// Insert New Element BEFORE
el.before(newEl);

// Insert New Element AFTER
el.after(newEl);

// Remove Element
el.remove();

// Remove Child
newEl.remove(); // This one wasnt tested but should work
Mister SirCode
fonte
5

Ou você pode simplesmente fazer:

referenceNode.parentNode.insertBefore( newNode, referenceNode )
referenceNode.parentNode.insertBefore( referenceNode, newNode )
olvlvl
fonte
Eu não teria pensado nessa abordagem. Prefiro usar a resposta mais direta de @ karim79 , mas é bom ter em mente.
Ben J
5

Etapa 1. Prepare elementos:

var element = document.getElementById('ElementToAppendAfter');
var newElement = document.createElement('div');
var elementParent = element.parentNode;

Etapa 2. Anexar após:

elementParent.insertBefore(newElement, element.nextSibling);
Malik Khalil
fonte
3

O método insertBefore () é usado como parentNode.insertBefore(). Então, para imitar isso e criar um método parentNode.insertAfter(), podemos escrever o seguinte código.

Javascript

Node.prototype.insertAfter = function(newNode, referenceNode) {
    return referenceNode.parentNode.insertBefore(
        newNode, referenceNode.nextSibling); // based on karim79's solution
};

// getting required handles
var refElem = document.getElementById("pTwo");
var parent = refElem.parentNode;

// creating <p>paragraph three</p>
var txt = document.createTextNode("paragraph three");
var paragraph = document.createElement("p");
paragraph.appendChild(txt);

// now we can call it the same way as insertBefore()
parent.insertAfter(paragraph, refElem);

HTML

<div id="divOne">
    <p id="pOne">paragraph one</p>
    <p id="pTwo">paragraph two</p>
</div>

Observe que estender o DOM pode não ser a solução certa para você, conforme declarado neste artigo .

No entanto, este artigo foi escrito em 2010 e as coisas podem ser diferentes agora. Então, decida por si próprio.

Método JavaScript insertAfter () DOM @ jsfiddle.net

Dmytro Dzyubak
fonte
2

Idealmente, insertAfterdeve funcionar de forma semelhante ao insertBefore . O código abaixo fará o seguinte:

  • Se não houver filhos, o novo Nodeserá anexado
  • Se não houver referência Node, o novo Nodeserá anexado
  • Se não há Node após a referência Node, o novo Nodeserá anexado
  • Se houver a referência Node tiver um irmão depois, o novo Nodeserá inserido antes desse irmão
  • Retorna o novo Node

Estendendo Node

Node.prototype.insertAfter = function(node, referenceNode) {

    if (node)
        this.insertBefore(node, referenceNode && referenceNode.nextSibling);

    return node;
};

Um exemplo comum

node.parentNode.insertAfter(newNode, node);

Veja o código em execução

Darlesson
fonte
2

Eu sei que esta pergunta já tem muitas respostas, mas nenhuma delas atendeu exatamente aos meus requisitos.

Eu queria uma função que tivesse exatamente o comportamento oposto deparentNode.insertBefore - isto é, ela deve aceitar um nulo referenceNode(o qual a resposta aceita não) e onde insertBeforeseria inserida no final dos filhos, que esta deve ser inserida no início , pois caso contrário haverá ' d não há como inserir no local inicial com esta função; o mesmo motivo é insertBeforeinserido no final.

Como um nulo referenceNodeexige que você localize o pai, precisamos conhecê-lo - insertBeforeé um método doparentNode , para que ele tenha acesso ao pai dessa maneira; como nossa função não funciona, precisamos passar o pai como parâmetro.

A função resultante é assim:

function insertAfter(parentNode, newNode, referenceNode) {
  parentNode.insertBefore(
    newNode,
    referenceNode ? referenceNode.nextSibling : parentNode.firstChild
  );
}

Ou (se você precisar, eu não recomendo), é claro que você pode aprimorar o Nodeprotótipo:

if (! Node.prototype.insertAfter) {
  Node.prototype.insertAfter = function(newNode, referenceNode) {
    this.insertBefore(
      newNode,
      referenceNode ? referenceNode.nextSibling : this.firstChild
    );
  };
}
mindplay.dk
fonte
0

Este código é um trabalho para inserir um item de link logo após o último filho existente para incluir um pequeno arquivo css

var raf, cb=function(){
    //create newnode
    var link=document.createElement('link');
    link.rel='stylesheet';link.type='text/css';link.href='css/style.css';

    //insert after the lastnode
    var nodes=document.getElementsByTagName('link'); //existing nodes
    var lastnode=document.getElementsByTagName('link')[nodes.length-1]; 
    lastnode.parentNode.insertBefore(link, lastnode.nextSibling);
};

//check before insert
try {
    raf=requestAnimationFrame||
        mozRequestAnimationFrame||
        webkitRequestAnimationFrame||
        msRequestAnimationFrame;
}
catch(err){
    raf=false;
}

if (raf)raf(cb); else window.addEventListener('load',cb);
Chetabahana
fonte
0

Você pode usar appendChild função para inserir após um elemento.

Referência: http://www.w3schools.com/jsref/met_node_appendchild.asp

Doug LN
fonte
Esta solução não trabalho para 2 tags p .. você não pode adicionar tag ap após o outro tag p com esta função ..
Mehregan Rahmani
0

uma implementação robusta do insertAfter.

// source: https://github.com/jserz/domPlus/blob/master/src/insertAfter()/insertAfter.js
Node.prototype.insertAfter = Node.prototype.insertAfter || function (newNode, referenceNode) {
  function isNode(node) {
    return node instanceof Node;
  }

  if(arguments.length < 2){
    throw(new TypeError("Failed to execute 'insertAfter' on 'Node': 2 arguments required, but only "+ arguments.length +" present."));
  }

  if(isNode(newNode)){
    if(referenceNode === null || referenceNode === undefined){
      return this.insertBefore(newNode, referenceNode);
    }

    if(isNode(referenceNode)){
      return this.insertBefore(newNode, referenceNode.nextSibling);
    }

    throw(new TypeError("Failed to execute 'insertAfter' on 'Node': parameter 2 is not of type 'Node'."));
  }

  throw(new TypeError("Failed to execute 'insertAfter' on 'Node': parameter 1 is not of type 'Node'."));

};

jszhou
fonte
Adicione algumas explicações com a resposta sobre como essa resposta ajuda o OP na correção do problema atual
#
Execute o código acima e insira um novoNode após o referenceNode especificado.
jszhou
0

Vamos lidar com todos os cenários

 function insertAfter(newNode, referenceNode) {
        if(referenceNode && referenceNode.nextSibling && referenceNode.nextSibling.nodeName == '#text')
            referenceNode = referenceNode.nextSibling;

        if(!referenceNode)
            document.body.appendChild(newNode);
        else if(!referenceNode.nextSibling)
            document.body.appendChild(newNode);
        else            
            referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);            
    }
Sami
fonte
0
if( !Element.prototype.insertAfter ) {
    Element.prototype.insertAfter = function(item, reference) {
        if( reference.nextSibling )
            reference.parentNode.insertBefore(item, reference.nextSibling);
        else
            reference.parentNode.appendChild(item);
    };
}
yavuzkavus
fonte
0

Você pode realmente usar um método chamado after()na versão mais recente do Chrome, Firefox e Opera. A desvantagem deste método é que o Internet Explorer ainda não o suporta.

Exemplo:

// You could create a simple node
var node = document.createElement('p')

// And then get the node where you want to append the created node after
var existingNode = document.getElementById('id_of_the_element')

// Finally you can append the created node to the exisitingNode
existingNode.after(node)

Um código HTML simples para testar que é:

<!DOCTYPE html>
<html>
<body>
     <p id='up'>Up</p>
    <p id="down">Down</p>
  <button id="switchBtn" onclick="switch_place()">Switch place</button>
  <script>
    function switch_place(){
      var downElement = document.getElementById("down")
      var upElement = document.getElementById("up")
      downElement.after(upElement);
      document.getElementById('switchBtn').innerHTML = "Switched!"
    }
  </script>
</body>
</html>

Como esperado, ele move o elemento para cima após o elemento para baixo

Anime no Sekai
fonte