Tengo una página estructurada así:
<body> <div class="one"> <div class="two"> <p class="three">Some text</p> </div> </div> <div class="four"> <div class="five"> <p class="six">Some other text</p> </div> </div> </body> Dado un selector, como .five , quiero eliminar todos los elementos del DOM mientras conservo la jerarquía de .four > .five > .six . En otras palabras, después de eliminar todos los elementos, debería quedarme con:
<body> <div class="four"> <div class="five"> <p class="six">Some other text</p> </div> </div> </body>Se me ocurrió la siguiente solución a este problema:
function removeElementsExcept(selector) { let currentElement = document.querySelector(selector) while (currentElement !== document.body) { const parent = currentElement.parentNode for (const element of parent.children) { if (currentElement !== element) { parent.removeChild(element) } } currentElement = parent } }Esto funciona lo suficientemente bien para el caso anterior, para el cual he creado un JSfiddle .
Sin embargo, cuando intento ejecutarlo en una página web más compleja como https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild con una llamada como removeElementsExcept('#sect1') , esperaría que solo el div azul que contiene el texto "Nota: siempre que sea una referencia ..." y su contenido interno se mantenga en la página. Sin embargo, si intenta ejecutar esto, muchos otros elementos se mantienen en la página junto con el div azul también.
¿Qué estoy haciendo incorrectamente en mi función?
Esto sucede porque está modificando la colección que se está iterando. Puede evitar esto ajustando manualmente el índice que se usa para mirar a los niños.
function removeElementsExcept(selector) { let currentElement = document.querySelector(selector) while (currentElement !== document.body) { const parent = currentElement.parentNode; let idx = 0; while (parent.children.length > 1) { const element = parent.children[idx]; if (currentElement !== element) { parent.removeChild(element) } else { idx = 1; } } currentElement = parent } }parent.removeChild(element) cambia la longitud de la colección iterada para que se omitan los elementos. Puede usar [...parent.children] para distribuir HTMLCollection en una matriz, haciéndolo seguro para las eliminaciones.
Otro enfoque consiste en crear un conjunto de nodos que desee conservar recorriendo todos los nodos secundarios y todos los nodos principales del elemento de destino. Luego elimine todos los demás nodos que no estén en el conjunto. No he ejecutado un punto de referencia.
const removeElementsExcept = el => { const keptEls = new Set(); for (let currEl = el; currEl; currEl = currEl.parentNode) { keptEls.add(currEl); } for (const childEl of [...el.querySelectorAll("*")]) { keptEls.add(childEl); } for (const el of [...document.querySelectorAll("body *")]) { if (!keptEls.has(el)) { el.remove(); } } }; removeElementsExcept(document.querySelector(".five")); .four { background: red; height: 100px; padding: 1em; } .five { background: blue; height: 100px; padding: 1em; } .six { background: yellow; height: 100px; padding: 1em; } <div class="one"> <div class="two"> <p class="three">Some text</p> </div> </div> <div class="four"> <div class="five"> <p class="six">Some other text</p> </div> </div>