Node#
Node.insertBefore()#
Metoda insertBefore()
dodaje przekazany węzeł przed wskazywane dziecko w danym węźle i zwraca referencję do dodawanego węzła.
Opis działania#
Samo wywołanie i poszczególne jego części najlepiej objaśnić na zapisie składniowym:
var other = node.insertBefore(other, child);
gdzie poszczególne człony oznaczają:
- other - referencja do przekazanego węzła, które dodawane jest przed wskazywane dziecko.
- node - węzeł będący obiektem kontekstu, który musi być rodzicem dla wskazywanego dziecka.
- other - referencja do przekazanego węzła, które dodawane jest przed wskazywane dziecko.
- child - referencja do wskazywanego dziecka, przed które dodawane jest przekazany węzłem lub wartość
null
.
Algorytm wywołania metody insertBefore(other, child)
nie jest skomplikowany. Dla lepszego zrozumienia tematu prezentuję go w całości:
- Zwróć wynik przed wstawienia other do obiektu kontekstu przed child.
Do wywołania metody insertBefore()
w powyższym zapisie składniowym potrzeba trzech odwołań: do rodzica, do nowego węzła oraz do dziecka. Składnię można nieco uprościć ograniczając się wyłącznie do dziecka i nowego węzła:
var other = child.parentNode.insertBefore(other, child);
Nie sprawdzi się to w sytuacji, kiedy przekazanym dzieckiem będzie wartość null
, ale jest to dopuszczalne, i w tym osobliwym przypadku pozwala zasymulować działanie metody Node.appendChild()
.
Żadna specyfikacja nie definiuje bezpośrednio metody insertAfter()
, ale możemy ją zaimplementować poprzez metodę insertBefore()
:
var other = parent.insertBefore(other, child.nextSibling);
Kiedy rodzic nie posiada żadnych dzieci lub wskazywane dziecko będące drugim argumentem jest ostatnim jego dzieckiem, to polecenie child.nextSibling
zwróci wartość null
, a to spowoduje, że dodawany węzeł będący pierwszym argumentem dołączony zostanie do rodzica i stanowić będzie jego jedyne lub ostatnie dziecko. Tym oto sposobem po raz kolejny otrzymujemy zachowanie identyczne z metodą Node.appendChild()
.
Analizując dokładnie wszystkie powiązane z metodą insertBefore()
algorytmy można zauważyć, że przekazany węzeł będący pierwszym argumentem nie może istnieć jednocześnie w kilku miejscach drzewa węzłów. Najpierw zostanie usunięty z drzewa węzłów, a następnie wstawiony w nowe miejsce drzewa węzłów (z ewentualnym skorygowaniem jego właściciela). Jeśli zależy nam na wstawieniu drugiego identycznego węzła należy go najpierw sklonować i dopiero dołączyć do konkretnego drzewa węzłów. Trzeba pamiętać, że kopia nigdy nie będzie zsynchronizowana z oryginałem (są to dwa osobne obiekty), każda zmiana oryginału nie będzie miała żadnego wpływu na wykonaną kopię.
Warto podkreślić, że węzeł docelowy, na którym wywołujemy metodę insertBefore()
, koniecznie musi być rodzicem dla przekazanego węzła stanowiącego drugi argument, ale nie może być jego dalszym przodkiem, w przeciwieństwie do metody Node.appendChild()
, która pozbawiona jest takich ograniczeń.
Prosty przykład:
<!DOCTYPE html>
<html>
<head>
<script>
// Uruchom po całkowitym załadowaniu dokumentu
window.onload = function(){
var ul1 = document.getElementById("ul1");
var ul2 = document.getElementById("ul2");
var newNode = ul1.getElementsByTagName("li")[0]; // referencja do pierwszego nowego węzła
var beforeNode = ul2.getElementsByTagName("li")[0]; // referencja do węzła poprzedzającego
// Manipulujemy drzewem po upływie 3 s
setTimeout(function(){
var ref = beforeNode.parentNode.insertBefore(newNode, beforeNode); // referencja do nowego węzła po jego dodaniu, to samo co newNode
var nextNode = document.createElement("li"); // kolejny nowy węzeł
nextNode.textContent = ref; // wartością tekstową uzyskaną po automatycznej konwersji ref będzie [object HTMLLIElement]
ul2.insertBefore(nextNode, null); // identyczne działanie jak appendChild()
}, 3000);
}
</script>
</head>
<body>
<p>Lista 1</p>
<ul id="ul1">
<li><a href="">Pierwszy odsyłacz</a></li>
<li><a href="">Drugi odsyłacz</a></li>
</ul>
<p>Lista 2</p>
<ul id="ul2">
<li><a href="">Drugi odsyłacz</a></li>
</ul>
</body>
</html>
Składnia Web IDL#
interface Node : EventTarget { Node insertBefore(Node other, Node? child); }