Elemento de eliminación DOM de JavaScript

198

Estoy tratando de probar si existe un elemento DOM, y si existe, elimínelo, y si no existe, créelo.

var duskdawnkey = localStorage["duskdawnkey"];
var iframe = document.createElement("iframe");
var whereto = document.getElementById("debug");
var frameid = document.getElementById("injected_frame");
iframe.setAttribute("id", "injected_frame");
iframe.setAttribute("src", 'http://google.com');
iframe.setAttribute("width", "100%");
iframe.setAttribute("height", "400");

if (frameid) // check and see if iframe is already on page
{ //yes? Remove iframe
    iframe.removeChild(frameid.childNodes[0]);
} else // no? Inject iframe
{
    whereto.appendChild(iframe);
    // add the newly created element and it's content into the DOM
    my_div = document.getElementById("debug");
    document.body.insertBefore(iframe, my_div);
}

Comprobar si existe funciona, crear el elemento funciona, pero eliminar el elemento no funciona. Básicamente todo lo que hace este código es inyectar un iframe en una página web haciendo clic en un botón. Lo que me gustaría que suceda es si el iframe ya está allí para eliminarlo. Pero por alguna razón estoy fallando.

Joshua Redfield
fuente
posible duplicado de JavaScript: eliminar elemento por id
Zaz

Respuestas:

339

removeChild debe invocarse en el padre, es decir:

parent.removeChild(child);

En su ejemplo, debería estar haciendo algo como:

if (frameid) {
    frameid.parentNode.removeChild(frameid);
}
casablanca
fuente
Gracias lo entendí justo antes de leer tu publicación. Tuve que cambiarlo a whereto.removeChild (whereto.childNodes [0]);
Joshua Redfield el
66
Eso también funcionaría suponiendo que su marco sea siempre el primer hijo del debugdiv. Usar parentNodees una solución más genérica que funcionará con cualquier elemento.
casablanca
1
Esta solución podría no ser suficiente. Si alguien está leyendo esto, eche un vistazo a la sugerencia de Glenn
Sebas
79

En la mayoría de los navegadores, hay una forma un poco más sucinta de eliminar un elemento del DOM que llamar .removeChild(element)a su padre, que es simplemente llamar element.remove(). A su debido tiempo, esto probablemente se convertirá en la forma estándar e idiomática de eliminar un elemento del DOM.

El .remove()método se agregó al DOM Living Standard en 2011 ( commit ) y desde entonces ha sido implementado por Chrome, Firefox, Safari, Opera y Edge. No era compatible con ninguna versión de Internet Explorer.

Si desea admitir navegadores más antiguos, deberá calzarlo. Esto resulta ser un poco irritante, tanto porque nadie parece haber hecho una cuña DOM de uso múltiple que contenga estos métodos, y porque no solo estamos agregando el método a un solo prototipo; es un método de ChildNode, que es solo una interfaz definida por la especificación y no es accesible para JavaScript, por lo que no podemos agregar nada a su prototipo. Por lo tanto, tenemos que encontrar todos los prototipos que heredan ChildNodey están definidos en el navegador y agregarlos .remove.

Aquí está la cuña que se me ocurrió, que he confirmado que funciona en IE 8.

(function () {
    var typesToPatch = ['DocumentType', 'Element', 'CharacterData'],
        remove = function () {
            // The check here seems pointless, since we're not adding this
            // method to the prototypes of any any elements that CAN be the
            // root of the DOM. However, it's required by spec (see point 1 of
            // https://dom.spec.whatwg.org/#dom-childnode-remove) and would
            // theoretically make a difference if somebody .apply()ed this
            // method to the DOM's root node, so let's roll with it.
            if (this.parentNode != null) {
                this.parentNode.removeChild(this);
            }
        };

    for (var i=0; i<typesToPatch.length; i++) {
        var type = typesToPatch[i];
        if (window[type] && !window[type].prototype.remove) {
            window[type].prototype.remove = remove;
        }
    }
})();

Esto no funcionará en IE 7 o inferior, ya que no es posible extender prototipos DOM antes de IE 8 . Sin embargo, me imagino que al borde de 2015 la mayoría de las personas no necesitan preocuparse por tales cosas.

Una vez que los haya incluido shim, podrá eliminar un elemento DOM elementdel DOM simplemente llamando

element.remove();
Mark Amery
fuente
1
Solo dejando esto aquí: polyfill.io/v2/docs/features/#Element_prototype_remove si incluye ese servicio polyfill automático, obtendrá soporte de vuelta a IE 7.
cumplido el
44
Esta es definitivamente la forma de hacerlo en 2017, siempre y cuando no te importe IE. Ver: developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
nevf
45

Parece que no tengo suficiente representante para publicar un comentario, por lo que tendrá que responder otra respuesta.

Cuando desvincula un nodo usando removeChild () o configurando la propiedad innerHTML en el padre, también debe asegurarse de que no haya nada más que lo haga referencia; de lo contrario, no se destruirá realmente y provocará una pérdida de memoria. Hay muchas formas en las que podría haber tomado una referencia al nodo antes de llamar a removeChild () y debe asegurarse de que las referencias que no han salido del alcance se eliminen explícitamente.

Doug Crockford escribe aquí que los controladores de eventos son una causa de referencias circulares en IE y sugiere eliminarlos explícitamente de la siguiente manera antes de llamar a removeChild ()

function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        for (i = a.length - 1; i >= 0; i -= 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}

E incluso si toma muchas precauciones, aún puede obtener pérdidas de memoria en IE como lo describe Jens-Ingo Farley aquí .

Y finalmente, no caigas en la trampa de pensar que la eliminación es la eliminación de Javascript . Parece ser sugerido por muchos, pero no hará el trabajo. Aquí hay una gran referencia sobre la comprensión de eliminar por Kangax.

Glenn Lawrence
fuente
1
tal vez puedas mostrar algunos jsFiddle para probar esto. Gracias
Muhaimin
1
Confirmo este comportamiento. Mi marco utiliza un árbol de mapeo de objetos Javascript sobre el diseño dom. Cada objeto js hace referencia a su elemento dom. A pesar de que llamo element.parentNode.removeChildpara eliminar elementos, se mantienen con vida y aún pueden ser referenciados. Simplemente no son visibles en el árbol dom regular.
Sebas
Sí, y luego quitar el puntero global a ese objeto de mapeo js desbloquea mágicamente el recolector de basura. Esta es una adición importante a la respuesta aceptada.
Sebas
11

Usar Node.removeChild () hace el trabajo por usted, simplemente use algo como esto:

var leftSection = document.getElementById('left-section');
leftSection.parentNode.removeChild(leftSection);

En DOM 4, se aplicó el método de eliminación, pero hay un soporte deficiente del navegador según W3C:

El método node.remove () se implementa en la especificación DOM 4. Pero debido al pobre soporte del navegador, no debe usarlo.

Pero puede usar el método remove si usa jQuery ...

$('#left-section').remove(); //using remove method in jQuery

También en nuevos marcos como puede usar condiciones para eliminar un elemento, por ejemplo, *ngIfen Angular y en React, la representación de diferentes vistas depende de las condiciones ...

Alireza
fuente
1
Si está creando un nodo modal en js usando createElement, solo asegúrese de verificar si el nodo existe antes de eliminarlo. if (leftSection) {..tu código} debería hacer el trabajo.
Afsan Abdulali Gujarati
0

Si está contento de usar la función brillante:

$("#foo").remove();

Para eliminar completamente el elemento del DOM.

Para eliminar los elementos sin eliminar datos y eventos, use esto en su lugar:

$("#foo").detach();

jQuery Docs

El .remove()método saca elementos del DOM. Úselo .remove()cuando desee eliminar el elemento en sí, así como todo lo que contiene. Además de los elementos en sí, se eliminan todos los eventos vinculados y los datos jQuery asociados con los elementos. Para eliminar los elementos sin eliminar datos y eventos, use .detach()en su lugar.

Aryan Beezadhur
fuente