Jak wstawić element po innym elemencie w JavaScript bez korzystania z biblioteki?

757

Jest insertBefore()w JavaScript, ale jak mogę wstawić element za innym elementem bez użycia jQuery lub innej biblioteki?

Xah Lee
źródło
4
jeśli potrzebujesz konkretnego przypadku ostatniego węzła potomnego - stackoverflow.com/questions/5173545/…
2
@AlanLarimer to świetnie. dzięki. czy wiesz, kiedy wprowadzono insertAdjacentElement?
Xah Lee,
1
Według MDN jest obsługiwany w IE8 i Firefox 48 (08 sierpnia 2016). Podążaj śladami : bugzilla.mozilla.org/show_bug.cgi?id=811259 -> w3.org/Bugs/Public/show_bug.cgi?id=19962 (14 marca 2016)
Alan Larimer

Odpowiedzi:

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

Gdzie referenceNodejest węzeł, po którym chcesz umieścić newNode. Jeśli referenceNodejest ostatnim dzieckiem w swoim elemencie nadrzędnym, to w porządku, ponieważ referenceNode.nextSiblingbędzie nulli insertBeforeobsługuje tę sprawę, dodając na końcu listy.

Więc:

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

Możesz to przetestować za pomocą następującego fragmentu:

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
źródło
8
Dzięki za świetną odpowiedź, ale czy nie jest mylące przerzucanie referencyjnego węzła i nowego węzła na liście argumentów? Dlaczego nie zastosować się do składni insertBefore?
GijsjanB
9
Ten fragment kodu nie obsługuje, jeśli ReferenceNode jest ostatnim dzieckiem, w którym powinien dołączyć appChild.
Brad Vogel,
72
Według MDN, jeśli element jest ostatni (a więc nextSibling ma wartość NULL), nowyNode zostanie dodany zgodnie z oczekiwaniami
electroCutie
9
referenceNode.nextElementSibling to lepsza opcja do użycia
Bhumi Singhal
8
@BhumiSinghal: Źle. insertBefore()współpracuje z węzłami tekstowymi. Dlaczego chcesz insertAfter()być inny? Należy utworzyć osobną parę nazwanych insertBeforeElement()i insertAfterElement()do tego celu.
7vujy0f0hy
116

Prosty JavaScript byłby następujący:

Dołącz przed:

element.parentNode.insertBefore(newElement, element);

Dołącz po:

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

Ale wrzuć tam kilka prototypów, aby ułatwić ich użycie

Budując następujące prototypy, będziesz mógł wywoływać te funkcje bezpośrednio z nowo tworzonych elementów.

  • newElement.appendBefore(element);

  • newElement.appendAfter(element);

.appendBefore (element) Prototyp

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

.appendAfter (element) Prototyp

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

Aby zobaczyć wszystko w akcji, uruchom następujący fragment kodu

Uruchom go na JSFiddle

Armando
źródło
4
Na rozszerzenie nazwy funkcji są mylące. Uważa, że ​​należy raczej nazwać appendMeBefore i appendMeAfter. Myślałem, że został użyty jak metoda appendChild () , np existingElement.appendAfter(newElement);. Zobacz, co mam na myśli w tym zaktualizowanym jsfiddle .
stomtech
2
Append After działa, ponieważ jeśli element.nextSibling nie ma następnego rodzeństwa, nextSibling ma wartość NULL, a następnie zostanie dołączone na końcu.
Stefan Steiger
45

insertAdjacentHTML + outerHTML

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

Plusy:

  • OSUSZACZ: nie musisz przechowywać węzła przedtem w zmiennej i używać go dwa razy. Jeśli zmienisz nazwę zmiennej, rzadziej będziesz ją modyfikować.
  • golfa lepsze niż insertBefore(nawet jeśli istniejąca nazwa zmiennej węzła ma długość 3 znaków)

Wady:

  • niższe wsparcie przeglądarki od nowszej wersji: https://caniuse.com/#feat=insert-adjacent
  • utraci właściwości elementu, takie jak zdarzenia, ponieważ outerHTMLkonwertuje element na ciąg. Potrzebujemy tego, ponieważ insertAdjacentHTMLdodaje treść z ciągów zamiast elementów.
Ciro Santilli
źródło
12
Jeśli masz już skonstruowany element, możesz użyć.insertAdjacentElement()
GetFree,
6
Od 2018 r. Obsługa przeglądarki wygląda dość solidnie: caniuse.com/#feat=insert-adjacent
madannes
To było miłe rozwiązanie, sugeruję, aby każdy
Mehregan Rahmani
37

Szybkie wyszukiwanie w Google ujawnia ten skrypt

// 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
źródło
29
Dla każdego, kto natknie się na ten skrypt, nie polecam go używać. Próbuje rozwiązać problemy, które natywne rozwiązanie @ karim79 już rozwiązuje. Jego skrypt jest szybszy i wydajniejszy - zdecydowanie polecam użycie tego skryptu zamiast tego.
James Long
10
Jako ogólna zasada w JavaScript, przeglądarka może wykonać zadanie szybciej niż cokolwiek, co możesz napisać. Chociaż oba rozwiązania są funkcjonalnie takie same, moje rozwiązanie JavaScript musi zostać przeczytane zrozumiałe dla przeglądarki, zanim będzie można z niego korzystać, i wymaga dodatkowej kontroli za każdym razem, gdy jest uruchamiane. Rozwiązanie oferowane przez karim79 zrobi to wszystko wewnętrznie, oszczędzając te kroki. Różnica będzie co najwyżej trywialna, ale jego rozwiązanie jest lepsze.
James Long
3
Innymi słowy, próbuje rozwiązać problem, który nie istnieje. Dodatkowa kontrola nie ma w sobie nic złego, ale przypuszczam, że nie propaguje ona najlepszego zrozumienia tych metod
1j01 23.03.15
3
Dosyć. Zostawiam skrypt tutaj, ponieważ pisałem coś takiego, ale zaakceptowana odpowiedź jest lepsza, pokazuje lepsze zrozumienie metod i jest szybsza. Nie ma powodu, aby zamiast tego użyć tej odpowiedzi - nie jestem nawet pewien, dlaczego wciąż zyskuje na popularności
James Long
3
Jeśli targetElement jest ostatnim elementem wśród rodzeństwa, wówczas targetElement.nextSiblingzwróci null. Gdy node.insertBeforejest wywoływany nulljako jako drugi argument, doda węzeł na końcu kolekcji. Innymi słowy, if(parent.lastchild == targetElement) {gałąź jest zbyteczna, ponieważ parent.insertBefore(newElement, targetElement.nextSibling);będzie poprawnie obsługiwać wszystkie przypadki, nawet jeśli na początku może się wydawać inaczej. Wielu już to zauważyło w innych komentarzach.
Rolf
26

Chociaż insertBefore()(patrz MDN ) jest świetny i zawiera większość odpowiedzi tutaj. Aby zwiększyć elastyczność i być bardziej precyzyjnym, możesz użyć:

insertAdjacentElement()(patrz MDN ) Pozwala to na odwołanie się do dowolnego elementu i wstawienie elementu, który ma zostać przeniesiony, dokładnie tam, gdzie chcesz:

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

Inne do rozważenia w podobnych przypadkach użycia: insertAdjacentHTML()iinsertAdjacentText()

Bibliografia:

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

nieco mniej
źródło
Naprawdę powinna dać tej odpowiedzi trochę miłości, to szybko zbliża się nowoczesne podejście do lat 2020.
serraosays
1
Dlaczego ta odpowiedź jest tak głęboko zakopana? Nagrodzę go kilkoma punktami, aby zwrócić większą uwagę.
Qwerty
16

Metoda node.after( doc ) wstawia węzeł za innym węzłem.

Dla dwóch węzłów DOM node1i node2,

node1.after(node2)wstawia node2po node1.

Ta metoda nie jest dostępna w starszych przeglądarkach, dlatego zwykle potrzebny jest wielopełniacz.

golopot
źródło
To wymaga trochę pracy ręcznej, aby zaimplementować jako działającą wstawkę Po tym, jednak niestety nie sądzę, aby działało to poprawnie.
Mister SirCode,
6

Rozwiązanie 2018 (Zła praktyka, przejdź do 2020 r.)

Wiem, że to pytanie jest starożytne, ale dla wszystkich przyszłych użytkowników, oto zmodyfikowany prototyp, jest to po prostu mikro-wypełnienie dla funkcji .insert Po tym, który nie istnieje, ten prototyp bezpośrednio dodaje nową funkcję baseElement.insertAfter(element);do prototypu Element:

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

Po umieszczeniu wypełniacza w bibliotece, treści lub po prostu w kodzie (lub w innym miejscu, do którego można się odwołać) Po prostu napisz document.getElementById('foo').insertAfter(document.createElement('bar'));


Rozwiązanie 2019 (brzydkie, przejdź do 2020 r.)

Nowa edycja: NIE WOLNO STOSOWAĆ PROTOTYPÓW. Zastępują one domyślną bazę kodu i nie są bardzo wydajne ani bezpieczne i mogą powodować błędy zgodności, ale jeśli dotyczy to projektów niekomercyjnych, nie powinno to mieć znaczenia. jeśli chcesz bezpieczną funkcję do użytku komercyjnego, po prostu użyj funkcji domyślnej. to nie jest ładne, ale działa:

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 


Rozwiązanie 2020

Aktualne standardy sieciowe dla ChildNode: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode

Jest obecnie w Living Standards i jest BEZPIECZNY.

W przypadku nieobsługiwanych przeglądarek skorzystaj z funkcji Polyfill: https://github.com/seznam/JAK/blob/master/lib/polyfills/childNode.js

Ktoś wspomniał, że Polyfill używa Protos, kiedy powiedziałem, że to zła praktyka. Są, szczególnie gdy są używane nieprawidłowo, podobnie jak moje rozwiązanie na 2018 rok. Jednak ta polifill znajduje się w Dokumentacji MDN i korzysta z bezpieczniejszej inicjalizacji i wykonania. Plus JEST dla starszych przeglądarek, w czasach, gdy nadpisywanie prototypów nie było takie złe.

Jak korzystać z rozwiązania 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
Pan SirCode
źródło
5

Lub możesz po prostu zrobić:

referenceNode.parentNode.insertBefore( newNode, referenceNode )
referenceNode.parentNode.insertBefore( referenceNode, newNode )
olvlvl
źródło
Nie pomyślałbym o takim podejściu. Wolałbym użyć bardziej bezpośredniej odpowiedzi @ karim79 , ale warto o tym pamiętać.
Ben J
5

Krok 1. Przygotuj elementy:

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

Krok 2. Dołącz po:

elementParent.insertBefore(newElement, element.nextSibling);
Malik Khalil
źródło
3

Metoda insertBefore () jest używana jak parentNode.insertBefore(). Aby to naśladować i stworzyć metodę parentNode.insertAfter(), możemy napisać następujący kod.

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>

Pamiętaj, że rozszerzenie DOM może nie być właściwym rozwiązaniem dla Ciebie, jak stwierdzono w tym artykule .

Jednak ten artykuł został napisany w 2010 roku i teraz może być inaczej. Zdecyduj więc sam.

JavaScript DOM insertAfter () metoda @ jsfiddle.net

Dmytro Dziubak
źródło
2

Idealnie insertAfterpowinien działać podobnie do insertBefore . Poniższy kod wykona następujące czynności:

  • Jeśli nie ma dzieci, nowe Nodejest dołączane
  • Jeśli nie ma odniesienia Node, nowe Nodejest dodawane
  • Jeśli nie ma Nodepo referencji Node, nowa Nodejest dołączana
  • Jeśli referencja Nodema później rodzeństwo, nowy Nodejest wstawiany przed tym rodzeństwem
  • Zwraca nowy Node

Rozsuwalny Node

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

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

    return node;
};

Jeden wspólny przykład

node.parentNode.insertAfter(newNode, node);

Zobacz działający kod

Darlesson
źródło
2

Wiem, że na to pytanie ma już zbyt wiele odpowiedzi, ale żadne z nich nie spełniło moich dokładnych wymagań.

Chciałem funkcji, która ma dokładnie odwrotne zachowanieparentNode.insertBefore - to znaczy musi zaakceptować wartość zerową referenceNode(czego nie przyjmuje zaakceptowana odpowiedź ) i gdzie insertBeforewstawiłaby na końcu dzieci, którą należy wstawić na początku , ponieważ w przeciwnym razie ' d nie można w żaden sposób wstawić w miejscu początkowym z tą funkcją; ten sam powód insertBeforewstawia na końcu.

Ponieważ wartość null referenceNodewymaga zlokalizowania elementu nadrzędnego, musimy znać element nadrzędny - insertBeforejest to metoda parentNode, więc ma on w ten sposób dostęp do elementu nadrzędnego; nasza funkcja nie, więc musimy przekazać parametr nadrzędny jako parametr.

Wynikowa funkcja wygląda następująco:

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

Lub (jeśli musisz, nie polecam) możesz oczywiście ulepszyć Nodeprototyp:

if (! Node.prototype.insertAfter) {
  Node.prototype.insertAfter = function(newNode, referenceNode) {
    this.insertBefore(
      newNode,
      referenceNode ? referenceNode.nextSibling : this.firstChild
    );
  };
}
mindplay.dk
źródło
0

Ten kod jest praca, aby wstawić właściwą pozycję Link po ostatnim istniejącym dziecka inline mały plik 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
źródło
0

Możesz użyć appendChildfunkcji do wstawienia po elemencie.

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

Doug LN
źródło
To rozwiązanie nie działa dla 2 tagów p .. nie można dodać tagu ap po innym tagu p za pomocą tej funkcji.
Mehregan Rahmani
0

solidna implementacja 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
źródło
Dodaj wyjaśnienie wraz z odpowiedzią na pytanie, w jaki sposób ta odpowiedź pomaga OP w rozwiązaniu bieżącego problemu
K
Uruchom powyższy kod, a następnie możesz wstawić nowy węzeł po określonym węźle referencyjnym.
jszhou
0

Pozwala obsłużyć wszystkie scenariusze

 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
źródło
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
źródło
0

Można tak naprawdę wywołać metodę after()w nowszej wersji Chrome, Firefox i Opera. Minusem tej metody jest to, że Internet Explorer jeszcze jej nie obsługuje.

Przykład:

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

Prosty kod HTML do przetestowania, który jest:

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

Zgodnie z oczekiwaniami przesuwa element w górę za elementem w dół

Anime no Sekai
źródło