vanilla - Come inserire un elemento dopo un altro elemento in JavaScript senza usare una libreria?




vba appendchild (12)

C'è insertBefore() in JavaScript, ma come posso inserire un elemento dopo un altro elemento senza usare jQuery o un'altra libreria?


Passaggio 1. Preparare gli elementi:

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

Passaggio 2. Aggiungi dopo:

elementParent.insertBefore(newElement, element.nextSibling);

Il JavaScript diretto sarebbe il seguente:

Aggiungi prima:

element.parentNode.insertBefore(newElement, element);

Aggiungi dopo:

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

Ma, Toss Alcuni prototipi in là per facilità d'uso

Costruendo i seguenti prototipi, sarai in grado di chiamare queste funzioni direttamente dagli elementi appena creati.

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

E, per vederlo tutto in azione, eseguire il seguente frammento di codice

/* Adds Element BEFORE NeighborElement */
Element.prototype.appendBefore = function(element) {
  element.parentNode.insertBefore(this, element);
}, false;

/* Adds Element AFTER NeighborElement */
Element.prototype.appendAfter = function(element) {
  element.parentNode.insertBefore(this, element.nextSibling);
}, false;


/* Typical Creation and Setup A New Orphaned Element Object */
var NewElement = document.createElement('div');
NewElement.innerHTML = 'New Element';
NewElement.id = 'NewElement';


/* Add NewElement BEFORE -OR- AFTER Using the Aforementioned Prototypes */
NewElement.appendAfter(document.getElementById('Neighbor2'));
div {
  text-align: center;
}
#Neighborhood {
  color: brown;
}
#NewElement {
  color: green;
}
<div id="Neighborhood">
  <div id="Neighbor1">Neighbor 1</div>
  <div id="Neighbor2">Neighbor 2</div>
  <div id="Neighbor3">Neighbor 3</div>
</div>

Eseguilo su JSFiddle


Gestiamo tutti gli scenari

 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);            
    }

Idealmente insertAfter dovrebbe funzionare in modo simile a MDN . Il seguente codice eseguirà quanto segue:

  • Se non ci sono bambini, il nuovo Node viene aggiunto
  • Se non c'è alcun Node riferimento, il nuovo Node viene aggiunto
  • Se non ci sono Node dopo il Node riferimento, il nuovo Node viene aggiunto
  • Se il Node riferimento è preceduto da un fratello, il nuovo Node viene inserito prima di tale fratello
  • Restituisce il nuovo Node

Estendere il Node

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

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

    return node;
};

Un esempio comune

node.parentNode.insertAfter(newNode, node);

Guarda il codice in esecuzione

// First extend
Node.prototype.insertAfter = function(node, referenceNode) {
    
    if (node)
        this.insertBefore(node, referenceNode && referenceNode.nextSibling);

    return node;
};

var referenceNode,
    newNode;

newNode = document.createElement('li')
newNode.innerText = 'First new item';
newNode.style.color = '#FF0000';

document.getElementById('no-children').insertAfter(newNode);

newNode = document.createElement('li');
newNode.innerText = 'Second new item';
newNode.style.color = '#FF0000';

document.getElementById('no-reference-node').insertAfter(newNode);

referenceNode = document.getElementById('no-sibling-after');
newNode = document.createElement('li');
newNode.innerText = 'Third new item';
newNode.style.color = '#FF0000';

referenceNode.parentNode.insertAfter(newNode, referenceNode);

referenceNode = document.getElementById('sibling-after');
newNode = document.createElement('li');
newNode.innerText = 'Fourth new item';
newNode.style.color = '#FF0000';

referenceNode.parentNode.insertAfter(newNode, referenceNode);
<h5>No children</h5>
<ul id="no-children"></ul>

<h5>No reference node</h5>
<ul id="no-reference-node">
  <li>First item</li>
</ul>

<h5>No sibling after</h5>
<ul>
  <li id="no-sibling-after">First item</li>
</ul>

<h5>Sibling after</h5>
<ul>
  <li id="sibling-after">First item</li>
  <li>Third item</li>
</ul>


O puoi semplicemente fare:

referenceNode.parentNode.insertBefore( newNode, referenceNode )
referenceNode.parentNode.insertBefore( referenceNode, newNode )


So che questa domanda ha già troppe risposte, ma nessuna di queste ha soddisfatto i miei requisiti precisi.

Volevo una funzione che avesse il comportamento esattamente opposto di parentNode.insertBefore - cioè, deve accettare un referenceNode null (che la risposta accettata non è) e dove insertBefore dovrebbe essere inserito alla fine dei child che deve essere inserito all'inizio , poiché altrimenti non ci sarebbe modo di inserire nella posizione iniziale con questa funzione; lo stesso motivo inserire prima gli inserti alla fine.

Dato che un referenceNode nullo richiede di localizzare il genitore, dobbiamo conoscere il genitore - insertBefore è un metodo del parentNode , quindi ha accesso al genitore in quel modo; la nostra funzione no, quindi avremo bisogno di passare il genitore come parametro.

La funzione risultante assomiglia a questo:

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

Oppure (se devi, io non lo consiglio) puoi ovviamente migliorare il prototipo del Node :

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

Una rapida ricerca su Google rivela questo 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);
    }
}

node1.after(node2) produce <node1/><node2/> ,

dove node1 e node2 sono nodi DOM.

.after() è un metodo molto nuovo [1] , quindi il supporto del browser potrebbe essere un problema.


insertAdjacentHTML + outerHTML

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

upsides:

  • DRYer: non è necessario memorizzare il nodo precedente in una variabile e utilizzarlo due volte. Se si rinomina la variabile, su meno occorrenze da modificare.
  • golf meglio di insertBefore (interrompi anche se il nome della variabile del nodo esistente è di 3 caratteri)

Svantaggi:

  • supporto browser inferiore da più recente: https://caniuse.com/#feat=insert-adjacent
  • perderà le proprietà dell'elemento come eventi perché outerHTML converte l'elemento in una stringa. insertAdjacentHTML abbiamo bisogno perché insertAdjacentHTML aggiunge contenuto da stringhe piuttosto che da elementi.

if( !Element.prototype.insertAfter ) {
    Element.prototype.insertAfter = function(item, reference) {
        if( reference.nextSibling )
            reference.parentNode.insertBefore(item, reference.nextSibling);
        else
            reference.parentNode.appendChild(item);
    };
}

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

Dove referenceNode è il nodo che si desidera inserire newNode dopo. Se referenceNode è l'ultimo figlio all'interno del suo elemento genitore, va bene, perché referenceNode.nextSibling sarà null e insertBefore manterrà quel caso aggiungendo alla fine dell'elenco.

Così:

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

Provalo qui.





append