Comment insérer un élément après un autre élément en JavaScript sans utiliser de bibliothèque?

758

Il y a insertBefore()en JavaScript, mais comment puis-je insérer un élément après un autre élément sans utiliser jQuery ou une autre bibliothèque?

Xah Lee
la source
4
si vous avez besoin du cas spécifique du tout dernier nœud enfant - stackoverflow.com/questions/5173545/…
2
@AlanLarimer c'est super. Merci. savez-vous quand est inséré insertAdjacentElement?
Xah Lee
1
Selon MDN, il est pris en charge dans IE8 et Firefox 48 (08 août 2016). Suivez la piste: bugzilla.mozilla.org/show_bug.cgi?id=811259 -> w3.org/Bugs/Public/show_bug.cgi?id=19962 (14 mars 2016)
Alan Larimer

Réponses:

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

Où se referenceNodetrouve le nœud que vous souhaitez placer newNode. Si referenceNodeest le dernier enfant de son élément parent, c'est parfait, car referenceNode.nextSiblingsera nullet insertBeforegère ce cas en ajoutant à la fin de la liste.

Donc:

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

Vous pouvez le tester à l'aide de l'extrait de code suivant:

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
la source
8
Merci pour une excellente réponse, mais n'est-il pas déroutant d'inverser referenceNode et newNode dans la liste des arguments? Pourquoi ne pas respecter la syntaxe insertBefore?
GijsjanB
9
Cet extrait de code ne gère pas si le referenceNode est le dernier enfant, dans lequel il doit ajouter child.
Brad Vogel,
73
Selon MDN si l'élément est le dernier (et donc nextSibling est nul), le newNode sera ajouté comme prévu
electroCutie
9
referenceNode.nextElementSibling est une meilleure option à utiliser
Bhumi Singhal
8
@BhumiSinghal: Faux. insertBefore()fonctionne avec des nœuds de texte. Pourquoi voulez-vous insertAfter()être différent? Vous devez créer une paire de fonctions distincte nommée insertBeforeElement()et insertAfterElement()pour cela.
7vujy0f0hy
116

Le JavaScript simple serait le suivant:

Ajouter avant:

element.parentNode.insertBefore(newElement, element);

Ajouter après:

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

Mais, jetez quelques prototypes là-dedans pour en faciliter l'utilisation

En construisant les prototypes suivants, vous pourrez appeler ces fonctions directement à partir des éléments nouvellement créés.

  • newElement.appendBefore(element);

  • newElement.appendAfter(element);

Prototype .appendBefore (élément)

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

Prototype .appendAfter (élément)

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

Et, pour tout voir en action, exécutez l'extrait de code suivant

Exécutez-le sur JSFiddle

Armando
la source
4
Les noms des fonctions d' extension sont trompeurs. Il pense qu'il devrait plutôt s'appeler appendMeBefore et appendMeAfter. Je pensais qu'elle était utilisée comme la méthode appendChild () , par exemple existingElement.appendAfter(newElement);. Voyez ce que je veux dire à ce jsfiddle mis à jour .
stomtech
2
Ajouter après fonctionne, car si element.nextSibling n'a pas de frère suivant, nextSibling est NULL, puis il s'ajoutera à la fin.
Stefan Steiger
45

insertAdjacentHTML + outerHTML

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

Avantages:

  • DRYer: vous n'avez pas besoin de stocker le nœud avant dans une variable et de l'utiliser deux fois. Si vous renommez la variable, sur moins d'occurrence à modifier.
  • golf mieux que le insertBefore(seuil de rentabilité même si le nom de variable de nœud existant est long de 3 caractères)

Inconvénients:

  • support du navigateur inférieur depuis le plus récent: https://caniuse.com/#feat=insert-adjacent
  • perdra les propriétés de l'élément, telles que les événements, car outerHTMLconvertit l'élément en chaîne. Nous en avons besoin car il insertAdjacentHTMLajoute du contenu à partir de chaînes plutôt que d'éléments.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
12
Si vous avez déjà construit l'élément, vous pouvez utiliser.insertAdjacentElement()
GetFree
6
Depuis 2018, la prise en charge du navigateur semble assez solide: caniuse.com/#feat=insert-adjacent
madannes
C'était une bonne solution, je suggère à tout le monde de lire ce xahlee.info/js/js_insert_after.html
Mehregan Rahmani
37

Une recherche rapide sur Google révèle ce 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
la source
29
Pour quiconque tombe sur ce script, je ne recommande pas de l'utiliser. Il tente de résoudre les problèmes que la solution native de @ karim79 résout déjà. Son script est plus rapide et plus efficace - je recommande fortement d'utiliser ce script au lieu de celui-ci.
James Long
10
En tant que règle générale en JavaScript, le navigateur peut effectuer une tâche plus rapidement que tout ce que vous pouvez écrire. Bien que les deux solutions soient fonctionnellement identiques, ma solution JavaScript doit être lue et comprise par le navigateur avant de pouvoir être utilisée et nécessite une vérification supplémentaire à chaque exécution. La solution offerte par karim79 fera tout cela en interne, en sauvant ces étapes. La différence sera au mieux insignifiante, mais sa solution est la meilleure.
James Long
3
En d'autres termes, il tente de résoudre un problème qui n'existe pas. Il n'y a rien d'intrinsèquement mauvais dans la vérification supplémentaire, mais je suppose qu'elle ne propage pas la meilleure compréhension de ces méthodes
1j01
3
Plutôt. Je laisse le script ici parce que c'est le genre de chose que j'avais l'habitude d'écrire, mais la réponse acceptée est la meilleure, montre une meilleure compréhension des méthodes et est plus rapide. Il n'y a aucune raison d'utiliser cette réponse à la place - je ne sais même pas pourquoi elle reçoit toujours des votes positifs
James Long
3
Si targetElement est le dernier élément parmi ses frères et soeurs, alors targetElement.nextSiblingretournera null. Lorsque node.insertBeforeest appelé avec nullcomme deuxième argument, il ajoutera le nœud à la fin de la collection. En d'autres termes, la if(parent.lastchild == targetElement) {branche est superflue, car parent.insertBefore(newElement, targetElement.nextSibling);elle traitera correctement tous les cas, même si elle peut sembler différente au premier abord. Beaucoup l'ont déjà souligné dans d'autres commentaires.
Rolf
26

Cependant insertBefore()(voir MDN ) est génial et référencé par la plupart des réponses ici. Pour plus de flexibilité et pour être un peu plus explicite, vous pouvez utiliser:

insertAdjacentElement()(voir MDN ) Cela vous permet de référencer n'importe quel élément et d'insérer l'élément à déplacer exactement où vous le souhaitez:

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

D'autres à considérer pour des cas d'utilisation similaires: insertAdjacentHTML()etinsertAdjacentText()

Références:

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

un peu moins
la source
Faut-il vraiment donner un peu d'amour à cette réponse, c'est l'approche moderne des années 2020 qui approche rapidement.
serraosays
1
Comment se fait-il que cette réponse soit enterrée si profondément? Je vais le récompenser de quelques points pour attirer davantage l'attention.
Qwerty
16

La méthode node.after( doc ) insère un nœud après un autre nœud.

Pour deux nœuds DOM node1et node2,

node1.after(node2)insère node2aprèsnode1 .

Cette méthode n'est pas disponible dans les anciens navigateurs, donc généralement un polyfill est nécessaire.

golopot
la source
Cela prend un peu de travail manuel à implémenter comme un insert fonctionnel après, cependant, malheureusement, je ne pense pas que cela fonctionnerait correctement.
Monsieur SirCode
6

Solution 2018 (mauvaise pratique, passez à 2020)

Je sais que cette question est ancienne, mais pour tous les futurs utilisateurs, voici un prototype modifié, ce n'est qu'un micro-remplissage pour la fonction .insertAfter qui n'existe pas, ce prototype ajoute directement une nouvelle fonction baseElement.insertAfter(element);au prototype Element:

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

Une fois que vous avez placé le polyfill dans une bibliothèque, un résumé ou simplement dans votre code (ou n'importe où ailleurs où il peut être référencé) document.getElementById('foo').insertAfter(document.createElement('bar'));


Solution 2019 (moche, passez à 2020)

Nouvelle édition: VOUS NE DEVEZ PAS UTILISER DE PROTOTYPES. Ils écrasent la base de code par défaut et ne sont pas très efficaces ou sûrs et peuvent provoquer des erreurs de compatibilité, mais si c'est pour des projets non commerciaux, cela ne devrait pas avoir d'importance. si vous voulez une fonction sûre pour une utilisation commerciale, utilisez simplement une fonction par défaut. ce n'est pas joli mais ça marche:

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 


Solution 2020

Normes Web actuelles pour ChildNode: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode

Son actuellement dans le niveau de vie et est sûr.

Pour les navigateurs non pris en charge, utilisez ce Polyfill: https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

Quelqu'un a mentionné que le Polyfill utilise Protos, quand j'ai dit que c'était une mauvaise pratique. Ils le sont, surtout lorsqu'ils sont mal utilisés, comme ma solution pour 2018. Cependant, ce polyfill est sur la documentation MDN et utilise une sorte d'initialisation et d'exécution qui est plus sûre. De plus, c'est pour la prise en charge de navigateurs plus anciens, à l'époque où l'écrasement de prototypes n'était pas si mal.

Comment utiliser la solution 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
Monsieur SirCode
la source
5

Ou vous pouvez simplement faire:

referenceNode.parentNode.insertBefore( newNode, referenceNode )
referenceNode.parentNode.insertBefore( referenceNode, newNode )
olvlvl
la source
Je n'aurais pas pensé à cette approche. Je préfère utiliser la réponse plus directe de @ karim79 , mais bon à garder à l'esprit.
Ben J
5

Étape 1. Préparez les éléments:

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

Étape 2. Ajouter après:

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

La méthode insertBefore () est utilisée comme parentNode.insertBefore(). Donc, pour imiter cela et créer une méthode, parentNode.insertAfter()nous pouvons écrire le code suivant.

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>

Notez que l'extension du DOM peut ne pas être la bonne solution pour vous, comme indiqué dans cet article .

Cependant, cet article a été écrit en 2010 et les choses pourraient être différentes maintenant. Alors décidez par vous-même.

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

Dmytro Dzyubak
la source
2

Idéalement, il insertAfterdevrait fonctionner de manière similaire à insertBefore . Le code ci-dessous effectuera les opérations suivantes:

  • S'il n'y a pas d'enfants, le nouveau Nodeest ajouté
  • S'il n'y a pas de référence Node, le nouveau Nodeest ajouté
  • S'il n'y a pas Nodeaprès la référence Node, le nouveau Nodeest ajouté
  • Si la référence Nodea un frère après, le nouveau Nodeest inséré avant ce frère
  • Renvoie le nouveau Node

Extension Node

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

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

    return node;
};

Un exemple courant

node.parentNode.insertAfter(newNode, node);

Voir le code en cours d'exécution

Darlesson
la source
2

Je sais que cette question a déjà beaucoup trop de réponses, mais aucune ne répond à mes exigences exactes.

Je voulais une fonction qui a le comportement exactement opposé deparentNode.insertBefore - c'est-à-dire qu'elle doit accepter un null referenceNode(ce que la réponse acceptée ne fait pas) et où insertBeforeinsérer à la fin des enfants celui-ci doit insérer au début , car sinon il ' d aucun moyen d'insérer à l'emplacement de départ avec cette fonction; la même raison insertBeforeinsère à la fin.

Puisqu'un null referenceNodevous oblige à localiser le parent, nous devons connaître le parent - insertBeforeest une méthode de laparentNode , donc il a accès au parent de cette façon; notre fonction ne fonctionne pas, nous devons donc passer le parent comme paramètre.

La fonction résultante ressemble à ceci:

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

Ou (si vous le devez, je ne le recommande pas), vous pouvez bien sûr améliorer le Nodeprototype:

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

Ce code permet d'insérer un élément de lien juste après le dernier enfant existant pour insérer un petit fichier 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
la source
0

Vous pouvez utiliser appendChild fonction pour insérer après un élément.

Référence: http://www.w3schools.com/jsref/met_node_appendchild.asp

Doug LN
la source
Cette solution ne fonctionne pas pour les balises 2 p .. vous ne pouvez pas ajouter de balise ap après une autre balise p avec cette fonction ..
Mehregan Rahmani
0

une implémentation robuste 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
la source
Ajoutez une explication avec la réponse pour savoir comment cette réponse aide OP à résoudre le problème actuel
ρяσѕρєя K
Exécutez le code ci-dessus, puis vous pouvez insérer un nouveau nœud après le nœud de référence spécifié.
jszhou
0

Permet de gérer tous les scénarios

 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
la source
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
la source
0

Vous pouvez en fait utiliser une méthode appelée after()dans une version plus récente de Chrome, Firefox et Opera. L'inconvénient de cette méthode est qu'Internet Explorer ne la prend pas encore en charge.

Exemple:

// 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 code HTML simple à tester qui est:

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

Comme prévu, il déplace l'élément vers le haut après l'élément vers le bas

Anime no Sekai
la source