¿Cómo insertar un elemento después de otro elemento en JavaScript sin usar una biblioteca?

758

Existe insertBefore()en JavaScript, pero ¿cómo puedo insertar un elemento después de otro elemento sin usar jQuery u otra biblioteca?

Xah Lee
fuente
44
si necesita el caso específico del último nodo hijo - stackoverflow.com/questions/5173545/…
2
@AlanLarimer eso es genial. Gracias. ¿sabes cuándo se introduce insertAdarestElement?
Xah Lee
1
Según MDN, es compatible con IE8 y Firefox 48 (08 de agosto de 2016). Sigue el camino: bugzilla.mozilla.org/show_bug.cgi?id=811259 -> w3.org/Bugs/Public/show_bug.cgi?id=19962 (14 de marzo de 2016)
Alan Larimer

Respuestas:

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

¿Dónde referenceNodeestá el nodo que quieres poner newNodedespués? Si referenceNodees el último hijo dentro de su elemento padre, está bien, porque referenceNode.nextSiblinglo será nully insertBeforemanejará ese caso al agregarlo al final de la lista.

Entonces:

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

Puede probarlo con el siguiente fragmento:

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
fuente
8
Gracias por una excelente respuesta, pero ¿no es confuso voltear referenceNode y newNode en la lista de argumentos? ¿Por qué no cumplir con la sintaxis insertBefore?
GijsjanB
99
Este fragmento de código no maneja si el ReferenceNode es el último elemento secundario, en el que debería agregar Child.
Brad Vogel
73
Según MDN, si el elemento es el último (y por lo tanto nextSibling es nulo), el nuevo nodo se agregará como se esperaba
electroCutie el
99
referenceNode.nextElementSibling es una mejor opción para ser utilizada
Bhumi Singhal
8
@BhumiSinghal: Incorrecto. insertBefore()trabaja con nodos de texto. ¿Por qué quieres insertAfter()ser diferente? Debería crear un par separado de funciones con el nombre insertBeforeElement()y insertAfterElement()para eso.
7vujy0f0hy
116

JavaScript directo sería el siguiente:

Añadir antes:

element.parentNode.insertBefore(newElement, element);

Añadir después:

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

Pero, arroje algunos prototipos allí para facilitar su uso

Al construir los siguientes prototipos, podrá llamar a estas funciones directamente desde los elementos recién creados.

  • newElement.appendBefore(element);

  • newElement.appendAfter(element);

.appendBefore (elemento) Prototipo

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

.appendAfter (elemento) Prototipo

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

Y, para verlo todo en acción, ejecute el siguiente fragmento de código

Ejecútalo en JSFiddle

Armando
fuente
44
Los nombres de las funciones de extensión son engañosos. Piensa que debería llamarse appendMeBefore y appendMeAfter. Pensé que se usaba como el método appendChild () , por ejemplo existingElement.appendAfter(newElement);. Vea lo que quiero decir en este jsfiddle actualizado .
stomtech
2
Agregar después funciona, porque si element.nextSibling no tiene un hermano próximo, nextSibling es NULL y luego se agregará al final.
Stefan Steiger
45

insertAdjacentHTML + outerHTML

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

Upsides:

  • SECADOR: no tiene que almacenar el nodo anterior en una variable y usarlo dos veces. Si cambia el nombre de la variable, en menos casos para modificar.
  • golf mejor que el insertBefore(descanso incluso si el nombre de la variable de nodo existente es de 3 caracteres de largo)

Desventajas:

  • Soporte de navegador más bajo desde más reciente: https://caniuse.com/#feat=insert-ad adyacente
  • perderá propiedades del elemento tales como eventos porque outerHTMLconvierte el elemento en una cadena. Lo necesitamos porque insertAdjacentHTMLagrega contenido de cadenas en lugar de elementos.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
12
Si ya tiene el elemento construido, puede usar.insertAdjacentElement()
GetFree
66
A partir de 2018, el soporte del navegador parece bastante sólido: caniuse.com/#feat=insert-ad adyacente
madannes
Esta fue una buena solución, sugiero que todos lean esto xahlee.info/js/js_insert_after.html
Rahmani
37

Una búsqueda rápida en Google revela este 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
fuente
29
Para cualquiera que se encuentre con este script, no recomiendo usarlo. Intenta resolver problemas que la solución nativa de @ karim79 ya resuelve. Su script es más rápido y más eficiente. Recomiendo encarecidamente usar ese script en lugar de este.
James Long
10
Como regla general en JavaScript, el navegador puede hacer una tarea más rápido que cualquier cosa que pueda escribir. Aunque las dos soluciones son funcionalmente iguales, mi solución JavaScript necesita ser leída y comprendida por el navegador antes de que pueda usarse y requiere una verificación adicional cada vez que se ejecuta. La solución ofrecida por karim79 hará todo esto internamente, guardando esos pasos. La diferencia será trivial en el mejor de los casos, pero su solución es la mejor.
James Long
3
En otras palabras, está intentando resolver un problema que no existe. No hay nada intrínsecamente incorrecto en la verificación adicional, pero supongo que no está propagando la mejor comprensión de estos métodos
1j01
3
Más o menos. Dejo el guión aquí porque es el tipo de cosas que solía escribir, pero la respuesta aceptada es la mejor, muestra una mejor comprensión de los métodos y es más rápida. No hay ninguna razón para usar esta respuesta en su lugar: ni siquiera estoy seguro de por qué todavía recibe votos positivos
James Long
3
Si targetElement es el último elemento entre sus hermanos, entonces targetElement.nextSiblingregresará null. Cuando node.insertBeforese llama con nullsu segundo argumento, agregará el nodo al final de la colección. En otras palabras, la if(parent.lastchild == targetElement) {rama es superflua, porque parent.insertBefore(newElement, targetElement.nextSibling);se ocupará adecuadamente de todos los casos, aunque al principio parezca lo contrario. Muchos ya lo han señalado en otros comentarios.
Rolf
26

Aunque insertBefore()(ver MDN ) es excelente y se hace referencia en la mayoría de las respuestas aquí. Para mayor flexibilidad y para ser un poco más explícito, puede usar:

insertAdjacentElement()(ver MDN ) Esto le permite hacer referencia a cualquier elemento e insertar el elemento a mover exactamente donde lo desee:

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

Otros a tener en cuenta para casos de uso similares: insertAdjacentHTML()yinsertAdjacentText()

Referencias

https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdarestElement https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdarestHTML https: // developer.mozilla.org/en-US/docs/Web/API/Element/insertAdarestText

un poco menos
fuente
Realmente debería darle un poco de amor a esta respuesta, es el enfoque moderno para la década de 2020 que se está acercando rápidamente.
serraosayos
1
¿Cómo es que esta respuesta está tan enterrada? Le recompensaré algunos puntos para atraer más atención.
Qwerty
16

El método node.after( doc ) inserta un nodo después de otro nodo.

Para dos nodos DOM node1y node2,

node1.after(node2)inserta node2después node1.

Este método no está disponible en navegadores antiguos, por lo que generalmente se necesita un polyfill.

golopot
fuente
Sin embargo, esto requiere un poco de trabajo manual para implementarlo como un inserto funcional, así que desafortunadamente no creo que esto funcione correctamente.
Señor SirCode
6

Solución 2018 (mala práctica, ir a 2020)

Sé que esta pregunta es antigua, pero para cualquier usuario futuro, aquí hay un prototipo modificado, esto es solo un micro polyfill para la función .insertAfter que no existe, este prototipo agrega directamente una nueva función baseElement.insertAfter(element);al prototipo Element:

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

Una vez que haya colocado el polyfill en una biblioteca, gist, o simplemente en su código (o en cualquier otro lugar donde pueda ser referenciado) Simplemente escriba document.getElementById('foo').insertAfter(document.createElement('bar'));


Solución 2019 (feo, vaya a 2020)

Nueva edición: NO DEBE USAR LOS PROTOTIPOS. Sobrescriben la base de código predeterminada y no son muy eficientes o seguros y pueden causar errores de compatibilidad, pero si es para proyectos no comerciales, no debería importar. Si desea una función segura para uso comercial, utilice una función predeterminada. no es bonito pero 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 


Solución 2020

Estándares web actuales para ChildNode: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode

Actualmente está en los estándares de vida y es SEGURO.

Para navegadores no compatibles, use este Polyfill: https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

Alguien mencionó que Polyfill usa Protos, cuando dije que eran malas prácticas. Lo son, especialmente cuando se usan incorrectamente, como mi solución para 2018. Sin embargo, ese polyfill está en la documentación de MDN y usa un tipo de inicialización y ejecución que es más seguro. Además, ES para soporte de navegador antiguo, en la época en que la sobrescritura de prototipos no era tan mala.

Cómo usar la Solución 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
Señor SirCode
fuente
5

O simplemente puedes hacer:

referenceNode.parentNode.insertBefore( newNode, referenceNode )
referenceNode.parentNode.insertBefore( referenceNode, newNode )
olvlvl
fuente
No hubiera pensado en ese enfoque. Prefiero usar la respuesta más directa de @ karim79 , pero es bueno tenerlo en cuenta.
Ben J
5

Paso 1. Preparar elementos:

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

Paso 2. Agregar después de:

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

El método insertBefore () se usa como parentNode.insertBefore(). Entonces, para imitar esto y hacer un método parentNode.insertAfter(), podemos escribir el siguiente 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>

Tenga en cuenta que extender el DOM podría no ser la solución adecuada para usted, como se indica en este artículo .

Sin embargo, este artículo fue escrito en 2010 y las cosas pueden ser diferentes ahora. Así que decide por tu cuenta.

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

Dmytro Dzyubak
fuente
2

Idealmente insertAfterdebería funcionar de manera similar a insertBefore . El siguiente código realizará lo siguiente:

  • Si no hay niños, Nodese agrega el nuevo
  • Si no hay referencia Node, Nodese agrega el nuevo
  • Si no hay Nodedespués de la referencia Node, Nodese agrega el nuevo
  • Si allí la referencia Nodetiene un hermano después, entonces el nuevo Nodese inserta antes de ese hermano
  • Devuelve el nuevo Node

Extensible Node

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

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

    return node;
};

Un ejemplo común

node.parentNode.insertAfter(newNode, node);

Ver el código en ejecución

Darlesson
fuente
2

Sé que esta pregunta ya tiene demasiadas respuestas, pero ninguna de ellas cumplió con mis requisitos exactos.

Quería una función que tenga el comportamiento exactamente opuesto deparentNode.insertBefore , es decir, debe aceptar un valor nulo referenceNode(que la respuesta aceptada no acepta ) y dónde insertBeforese insertaría al final de los hijos, este debe insertar al principio , ya que de lo contrario allí ' d no hay forma de insertar en la ubicación de inicio con esta función en absoluto; la misma razón se insertBeforeinserta al final.

Desde un nulo referenceNode requiere que ubique al padre, necesitamos conocer al padre - insertBeforees un método deparentNode , por lo que tiene acceso al padre de esa manera; nuestra función no lo hace, por lo que tendremos que pasar el padre como parámetro.

La función resultante se ve así:

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

O (si es necesario, no lo recomiendo), por supuesto, puede mejorar el Nodeprototipo:

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

Este código es un trabajo para insertar un elemento de enlace justo después del último elemento secundario existente para incluir un pequeño archivo 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
fuente
0

Puedes usar appendChild función para insertar después de un elemento.

Referencia: http://www.w3schools.com/jsref/met_node_appendchild.asp

Doug LN
fuente
Esta solución no funciona para 2 etiquetas p ... no puede agregar una etiqueta ap después de otra etiqueta p con esta función ...
Mehregan Rahmani
0

Una implementación robusta de 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
fuente
Agregue alguna explicación con la respuesta de cómo esta respuesta ayuda a OP a solucionar el problema actual
ρяσѕρєя K
Ejecute el código anterior, luego puede insertar un nuevo nodo después del nodo de referencia especificado.
jszhou
0

Vamos a manejar todos los escenarios

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

En realidad, puede utilizar un método llamado after()en la versión más reciente de Chrome, Firefox y Opera. La desventaja de este método es que Internet Explorer aún no lo admite.

Ejemplo:

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

Un código HTML simple para probar que es:

<!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 se esperaba, mueve el elemento hacia arriba después del elemento hacia abajo

Anime no Sekai
fuente