2013-08-29 8 views
15

ich jquery-ui Tabs bin mit und ich habe ein Problem, das auftritt, wenn ein Tab entfernt wurde. Die Registerkarte scheint zusammen mit ihrem Inhalt div entfernt zu werden, aber wenn Sie in Chrome DevTools Profiles den Heap betrachten (nachdem eine Registerkarte entfernt wurde), werden Sie sehen, dass die Tab li und div -Elemente immer noch vorhanden, aber getrennt sind . Im Laufe der Zeit führt das wiederholte Hinzufügen/Entfernen von Tabs dazu, dass sich diese Elemente ansammeln. Wenn Sie eine Registerkarte 10mal Fügen Sie zum Beispiel, gibt es 10 freistehende div Elemente und 10 freistehende li Elemente in dem Heap-Snapshot zeigt nach oben:Kann nicht zur Reinigung freistehende DOM-Elemente scheinen

Heap snapshot with detached elements

Ich habe folgende Beobachtungen:

TabLabel = Marionette.ItemView.extend({ 
    template: "#tab-label", 
    tagName: "li", 
    events: { 
     "click .ui-icon-close": "closeTab" 
    }, 
    closeTab: function(e) { 
     this.$el.contents().remove(); 
     this.model.collection.remove(this.model); 
     $("#main-container").tabs("refresh"); 
     this.close(); 
    } 
}); 

TabContainer = Marionette.ItemView.extend({ 
    template: "#tab-container", 
    tagName: "div", 
    onBeforeRender: function() { 
     this.$el.attr("id", "div-" + this.id); 
    }, 
    onClose: function() { 
     // This removes the region that contains the container 
     App.layout.removeRegion(this.containerRegion); 
    } 
}); 

TabLabels = Marionette.CollectionView.extend({ 
    tagName: "ul" 
}); 

TabContainers = Marionette.CollectionView.extend({ 
    tagName: "div" 
}); 

die Ansichten wie so instanziiert werden:

tabs = new TabsCollection(); // Create a new collection instance 

var tabLabelView = new TabLabels({ 
    itemView: TabLabel, 
    collection: tabs 
}); 

var tabContainerView = new TabContainers({ 
    itemView: TabContainer, 
    collection: tabs 
}); 

wie Sie sehen können, die Ansichten beide auf die gleiche Sammlung verweisen; Jedes Modell in der Sammlung kann als eine einzelne Registerkarte dargestellt werden (es passiert einfach, dass das Modell die notwendigen Informationen enthält, um die Tabs von jquery-ui zu erfüllen). Die Ansichten sind in einer Region via Marionette.Layout ... ziemlich Standard. Das Hinzufügen einer Registerkarte erfolgt durch Klicken auf eine Verknüpfung im Registerkartencontainer. All dies fügt der Sammlung ein weiteres Modell hinzu und ruft dann Registerkarten ("refresh") auf dem Hauptcontainer auf, wodurch die neue Registerkarte angezeigt wird. Das Entfernen einer Registerkarte erfolgt durch Klicken auf ein "X" -Symbol in der oberen rechten Ecke der Registerkarte.

Ich habe viel Zeit damit verbracht, dieses Leck aufzuspüren, und ich kann nicht herausfinden, ob es ein Problem in meinem Code ist (die Art, wie ich Ansichten/Modelle schließe/etc.) Oder ob Es ist ein Problem im Plugin jquery-ui tabs.

Gedanken? Danke im Voraus!

Update # 1 Wie angefordert, hier ist eine jsfiddle zeigt das Problem - schließen Sie einfach die Tabs und Sie werden sehen, dass abgelöste Elemente zurückgelassen werden.

Auch ein Screenshot:

enter image description here

Update # 2 Dies scheint Widget ein Leck in dem jquery-ui Tabs zu sein. Das gleiche Verhalten tritt in der widget demonstration auf der Website jquery-ui auf. Ich habe ein paar Tabs und schloss sie dann heraus und sicher genug, sie beharrte:

enter image description here

ich dies mit der neuesten getestet haben (zum Zeitpunkt des Schreibens dieses Artikels) Version von jQuery UI (1.10.3) und die vorherige Version (1.10.2).

+0

Kannst du eine jsfiddle veröffentlichen, die das demonstriert? – Rooster

+2

Ich frage mich, ob das Problem ist, dass Event-Handler nicht entfernt wird –

+0

@JaniHartikainen Ich dachte, dass könnte das Problem sein, aber ich habe versucht, mehrere Permutationen von unbind() in der close-Funktion aufrufen und die Ergebnisse sind die gleichen. – musashiXXX

Antwort

3

So fixiere ich schließlich dieses Problem (schon vor einiger Zeit) durch zwei Dinge zu tun:

  1. Notwasserung jQueryUI zugunsten von Bootstrap
  2. die CloseTab Funktion ändern (das Original jsFiddle sehen) an folgenden :

    closeTab: function (e) { 
        e.stopPropagation(); 
        e.preventDefault(); 
        this.model.collection.remove(this.model); 
        this.close(); 
    } 
    

In diesem Code-Schnipsel sind stopPropagation und prevent wirklich, was dieses Element gestoppt aus Bleibt getrennt (und akkumuliert bei nachfolgenden Hinzufügen/Entfernen) im DOM. Zusammenfassend: Dieses Problem wurde dadurch verursacht, dass stopPropagation/preventDefault für das Ereignisobjekt nicht aufgerufen wurde, nachdem es ausgelöst wurde. Ich habe die jsFiddle so aktualisiert, dass sie die Registerkarte Elemente korrekt entfernt und für die Nachwelt, hier ist ein Screenshot von dem Ergebnis:

Updated jsFiddle

Wie Sie sehen können, keine der Registerkarte Elemente abgelöst werden, die nach dem Klick "X", um sie zu schließen. Die einzigen gelösten Elemente sind diejenigen, die von der jsFiddle-Schnittstelle kommen.

3

Gibt es einen Grund, warum Sie this.$el.contents().remove() statt this.$el.empty() verwenden?

Mit this.$el.empty() in diesem jsFiddle von Ihnen schienen den freistehenden NodeList zu beheben.

Ein paar Notizen Speicherprofilierungs:

  • Uhr http://www.youtube.com/watch?v=L3ugr9BJqIs
  • Verwenden Sie die 3 Schnappschüsse Methode 2 ist nicht genug. Was bedeutet das?
    • starten frisch, Inkognito-Modus und erfrischt
    • Snapshot (Zwangs- GC jedes Mal, wenn Snapshot passieren wird)
    • etwas tun, Snapshot (gc)
    • etwas ähnliches tun, Snapshot (gc)
    • Vergleichen Schnappschuss 2 mit Snapshot-1, Deltas finden mit +
    • Zusammenfassung und zwischen Snapshots zugeordnet Objekte auswählen 1 und 2 für Snapshot 3
    • Suchen Sie nach Sachen, die Sie gefunden haben, die 2 und 1 vergleichen, die nicht dort sein sollten. Dies sind die Lauch

ich gefunden habe, Fälle, in denen jQuery scheint zu Porree, weil sie den aktuellen jQuery-Objekt in .prevObject sparen, wenn einige Operationen zu tun wie .add() aufrufen. Vielleicht diesen Anruf zu .contents() machen einige funky Magie.

+0

Ich habe dies getestet, indem ich .empty() anstelle von .contents(). remove() verwendet habe, und die Ergebnisse sind leider dieselben. – musashiXXX