Backbone: doppelte Ereignisse, wenn die Ansicht zweimal instanziiert wird

Erstellt am 5. Feb. 2012  ·  9Kommentare  ·  Quelle: jashkenas/backbone

Wenn ich eine Ansicht definiere (über Backbone.View.extend) und sie zweimal instanziiere (über new), wenn ein Ereignis einmal auf jedem ivies-Objekt auftritt, wird es zweimal ausgelöst.

Kurzes Beispiel:

<html>
<head>
    <script type="text/javascript" src="js/jquery-1.7.1.js"></script>
    <script type="text/javascript" src="js/underscore-1.3.1.js"></script>
    <script type="text/javascript" src="js/backbone-0.9.1.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/javascript">
        testview = Backbone.View.extend ({
            el: '#test',
             events: {'click .test': 'doTest'},
             doTest: function() {alert('test')},
             render: function() {$('#test').append($('<a>').attr('href', '#').addClass('test').append('test'));}});
        view_one = new testview;
        view_two = new testview;
        view_one.render();
    </script>
    </body>
</html>

Alle 9 Kommentare

Warum instanziieren Sie es aus Neugier zweimal? Befinden Sie sich in einer mobilen Ansicht oder etwas, bei dem die erste Instanz im Ansichtsfenster durch eine andere Ansicht ersetzt wird, und wenn der Benutzer zu dieser ersten Ansicht zurückkehrt, erhalten Sie doppelte Bindungen?

So ähnlich. Ich habe eine Home-Ansicht, die verschiedene Endpunkte aufruft, wenn der Benutzer angemeldet ist oder nicht. Die Ereignisbindungen sind für die Login- / Logout-Buttons. Beide Ansichten werden instanziiert, aber es wird jeweils nur eine gerendert. Wenn sie sich an- oder abmelden, wechsle ich zur gleichen Ansicht, aber in einem anderen Modus. Hoffe das ist klar genug.

Mir ist immer noch nicht ganz klar, warum Sie beide Ansichten gleichzeitig instanziiert haben. Wenn beide an dasselbe bereits vorhandene Element im Dom gebunden sind, bedeutet dies, dass es doppelte Ereignisse geben wird. Dies ist nicht wirklich ein Fehler, sondern nur die Funktionsweise von Ereignissen und insbesondere der Ereignisdelegierung.

Wenn Sie eine Ansicht für ein bereits vorhandenes Element instanziieren, müssen Sie diese Ereignisse speziell aufheben, oder sie bleiben bestehen, bis der Elementknoten selbst aus dem Dom entfernt wird.

Nun, es schien eine gute Idee zu sein, beide Ansichten während der Initialisierung zu instanziieren, beide an dasselbe Root-Element im DOM zu binden und dann das eine oder das andere entsprechend dem Anmeldemodus zu rendern und beim Rendern die Elemente des anderen ersetzen zu lassen. Ich denke, es gibt einen besseren Weg, dies nach Ihren Kommentaren zu tun.

Ich würde Ansichten instanziieren, wenn Sie sie brauchen. Wenn eine Ansicht nicht verwendet wird, ist es nicht erforderlich, dass sie Speicher beansprucht und möglicherweise Nebenwirkungen wie Sie sehen.

Ich neige dazu, dieses Muster nicht zu verwenden:

var View = Backbone.View.extend ({
    el: '#test',
    events: 
    {
        'click .test': 'onClick'
    },
    onClick: function(event) 
    { 
        ... 
    }
});

view = new View;
view.render();

aber stattdessen neige ich dazu, dieses Muster zu verwenden, genau um Zombie-Ansichten zu vermeiden, die zu doppelten Ereignissen führen

var View = Backbone.View.extend ({
    events: 
    {
        'click .test': 'onClick'
    },
    onClick: function(event) 
    { 
        ... 
    }
});

view = new View;
$('#target').append(view.render().el);

Der einzige Ort, an dem ich Ihr erstes Muster verwenden würde, befindet sich in der Chrome-Ansicht der Anwendung, die die GUI instanziiert:

var Application = Backbone.View.extend({
    el: '#wrapper',
    initialize: function (options)
    {
        this.render();
    }
)};

$(document).ready(function () {
    window.application = new Application();
});

dito zu dem, was @vincentbriglia darüber gesagt hat, el nicht zu definieren und die Ansicht ein eigenes Element generieren zu lassen. Das mache ich auch zu 95 %. Wenn Sie jedoch el und die Ereignisse beim Entfernen bereinigen möchten, können Sie Ihre eigene Backbone.View.destroy() Methode mit einem .off() für jedes entsprechende on() und jede Veranstaltung in events: {}

zum Beispiel:

var MyView = Backbone.View.extend({

  initialize: function() {
    this.model.on('change', this.render, this);
  },

  render: function() {
    return this;
  },

  destroy: function() {
    this.remove();
    this.model.off('change', this.render, this);
  }
})

Danke @malandrew und @vincentbriglia , das hilft wirklich.

Nur um dies für die Nachwelt zu aktualisieren ... Ich habe der View-Klasse eine Destroy-Methode hinzugefügt, die wie folgt aussieht

           destroy: function() {
                this.undelegateEvents();
            }

Dann zerstöre ich einfach die aktuelle Ansicht (State.view), wenn ich instanziiere ().

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen