Kontynuacja lekcji poprzedniej, piszemy już coraz lepszy i coraz bardziej reaktywny czysty JavaScript, niedługo całą dokumentację MDN będziemy cytować z pamięci. Do dzieła!
Ok, poprzedni markup:
<ul id="list">
Languages to learn:
<li>C# <button class="btn-del">X</button></li>
<li>Java <button class="btn-del">X</button></li>
<li>Scala <button class="btn-del">X</button></li>
<li>Perl <button class="btn-del">X</button></li>
<li>Ruby <button class="btn-del">X</button></li>
</ul>
I poprzedni JS z delegacją eventów:
let ul = document.querySelector("#list");
ul.addEventListener("click", function(e){
if(!e.target.matches('button.btn-del'))
return;
e.target.closest("li").remove();
if(e.currentTarget.childElementCount === 0)
e.currentTarget.removeChild(e.currentTarget.firstChild);
});
Teraz postaramy się ogarnąć zmianę dzieci-elementów za pomocą mutation observera:
const observer = new MutationObserver(callback);
function callback(mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === "childList") {
console.log("A child node has been added or removed.");
console.log(mutation.target);
}
}
}
observer.observe(ul, { childList: true});
Działa? Działa. Z naszą znajomością dokumentacji i mając target, który jest elementem i węzłem już dalej sobie poradzimy:
const observer = new MutationObserver(callback);
function callback(mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === "childList") {
let _target = mutation.target;
if(_target.childElementCount === 0){
_target.removeChild(_target.firstChild);
}
}
}
}
observer.observe(ul, { childList: true});
Ok, mamy error – dlaczego? Cóż, mutacja zostaje dokonana, warunek zostaje spełniony, zaś firstChild już nie istnieje (po usunięciu go). Możemy to naprawić:
const observer = new MutationObserver(callback);
function callback(mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === "childList") {
let _target = mutation.target;
if(
_target.childElementCount === 0
&&
_target.childNodes.length > 0
){
_target.removeChild(_target.firstChild);
}
}
}
}
observer.observe(ul, { childList: true});
Możemy ten kod jeszcze ulepszyć:
const observer = new MutationObserver(callback);
function callback(mutationsList, observer) {
for (let mutation of mutationsList) {
switch(mutation.type) {
case 'childList':
let _target = mutation.target;
if(
_target.childElementCount === 0
&&
_target.childNodes.length > 0
){
_target.removeChild(_target.firstChild);
break;
}
default:
console.log("unknown mutation");
}
}
}
observer.observe(ul, { childList: true});
Od razu wygląda ładniej. Więcej w następnych lekcjach.