2012-01-12 26 views
136

Sto provando a verificare se esiste un elemento DOM, e se esiste esiste cancellarlo e, se non esiste, crearlo.JavaScript DOM rimuovi elemento

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); 
} 

Controllare se esiste funziona, la creazione dell'elemento funziona, ma l'eliminazione dell'elemento non lo fa. Fondamentalmente tutto questo codice fa iniettare un iframe in una pagina web facendo clic su un pulsante. Quello che mi piacerebbe accadesse è se l'iframe è già lì per eliminarlo. Ma per qualche ragione sto fallendo.

+0

possibile duplicato di [JavaScript: rimuovere elemento da id] (http://stackoverflow.com/questions/3387427/javascript-remove-element-by-id) – Zaz

risposta

253

removeChild dovrebbero essere invocati sul genitore, vale a dire:

parent.removeChild(child); 

Nel tuo esempio, si dovrebbe fare qualcosa di simile:

if (frameid) { 
    frameid.parentNode.removeChild(frameid); 
} 
+0

Grazie capito fuori proprio prima che legga il tuo post. Dovuto cambiarlo in whereto.removeChild (whereto.childNodes [0]); –

+6

Ciò funzionerebbe anche assumendo che il tuo frame sia sempre il primo figlio del div di 'debug'. L'uso di 'parentNode' è una soluzione più generica che funzionerà con qualsiasi elemento. – casablanca

+1

Questa soluzione potrebbe non essere sufficiente. Se qualcuno sta leggendo questo per favore dai un'occhiata al suggerimento di Glenn – Sebas

37

sembra che io non ho abbastanza rep per pubblicare un commento, quindi un'altra risposta dovrà fare.

Quando si scollega un nodo utilizzando removeChild() o si imposta la proprietà innerHTML sul genitore, è necessario assicurarsi che non vi siano altri riferimenti che altrimenti non verranno effettivamente distrutti e porteranno ad una memoria perdita. Ci sono molti modi in cui potresti aver preso un riferimento al nodo prima di chiamare removeChild() e devi assicurarti che quei riferimenti che non sono usciti dall'ambito siano esplicitamente rimossi.

Doug Crockford scrive here che i gestori di eventi sono noti a causa di riferimenti circolari in IE e li suggerisce di rimuovere in modo esplicito come segue prima di chiamare 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 anche se si prende un sacco di precauzioni che si possono ancora ottenere perdite di memoria in IE come descritto da Jens-Ingo Farley here.

Infine, non cadere nella trappola di pensare che Javascript elimina è la risposta. Sembra essere suggerito da molti, ma non farà il lavoro. Here è un ottimo riferimento per capire eliminare di Kangax.

+1

forse puoi mostrare un po 'di jsFiddle per dimostrarlo. Grazie – Muhaimin

+1

confermo questo comportamento. Il mio framework utilizza un albero di mapping di oggetti Javascript sul layout dom. Ogni oggetto js fa riferimento al suo elemento dom. Anche se chiamo 'element.parentNode.removeChild' per rimuovere gli elementi, rimangono vivi e possono ancora essere referenziati. Semplicemente non sono visibili nel regolare albero delle dom. – Sebas

+0

Sì, e quindi rimuovere il puntatore globale su quell'oggetto di mappatura js sblocca magicamente il garbage collector. Questa è un'aggiunta importante alla risposta accettata. – Sebas

39

Nella maggior parte dei browser, c'è un modo leggermente più succinto di rimuovere un elemento dal DOM piuttosto che chiamare .removeChild(element) sul suo genitore, che è chiamare semplicemente element.remove(). A tempo debito, questo probabilmente diventerà il modo standard e idiomatico di rimuovere un elemento dal DOM.

Il metodo .remove() è stato aggiunto al DOM Living Standard nel 2011 (commit) e da allora è stato implementato da Chrome, Firefox, Safari, Opera e Edge. Non era supportato in nessuna versione di Internet Explorer.

Se si desidera supportare i browser meno recenti, è necessario ridurlo. Questo risulta essere un po 'irritante, sia perché nessuno sembra aver creato uno shim DOM per tutti gli usi che contiene questi metodi, e perché non stiamo semplicemente aggiungendo il metodo a un singolo prototipo; è un metodo di ChildNode, che è solo un'interfaccia definita dalla specifica e non è accessibile a JavaScript, quindi non possiamo aggiungere nulla al suo prototipo. Quindi abbiamo bisogno di trovare tutti i prototipi che ereditano da ChildNode e sono effettivamente definiti nel browser, e aggiungere .remove a loro.

Ecco lo shim che ho trovato, che ho confermato funziona in 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; 
     } 
    } 
})(); 

Questo non funziona in IE 7 o inferiore, dal momento che extending DOM prototypes isn't possible before IE 8. Immagino, però, che sull'orlo del 2015 la maggior parte delle persone non abbia bisogno di preoccuparsi di queste cose.

Una volta che li hai incluso spessore, sarete in grado di rimuovere un elemento DOM element dal DOM semplicemente chiamando

element.remove(); 
+1

Basta lasciare questo qui: https://polyfill.io/v2/docs/features/#Element_prototype_remove se si include quel servizio di polyfill automagic si otterrà il supporto di nuovo a IE 7. – complistic

+2

Questo è sicuramente il modo di farlo nel 2017 come Finché non ti importa di IE. Vedi: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove – nevf

1

Utilizzando Node.removeChild() fa il lavoro per voi, è sufficiente utilizzare qualcosa di simile:

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

In DOM 4, il metodo remove applicato, ma non v'è un supporto povero del browser in base al W3C:

Il metodo node.remove() è implementato nella specifica DOM 4. Ma a causa dello scarso supporto del browser, non dovresti usarlo.

Ma è possibile utilizzare il metodo di rimozione, se si utilizza jQuery ...

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

anche in nuovi contesti, come è possibile utilizzare le condizioni per rimuovere un elemento, ad esempio *ngIf in angolare e nel reagire, rendendo viste diverse, dipende dalle condizioni ...