Backbone: duplikat acara saat membuat tampilan dua kali

Dibuat pada 5 Feb 2012  ·  9Komentar  ·  Sumber: jashkenas/backbone

Ketika saya mendefinisikan tampilan (melalui Backbone.View.extend) dan membuat instance dua kali (melalui baru), ketika suatu peristiwa terjadi sekali pada setiap objek ivie, itu dipecat dua kali.

Contoh singkat:

<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>

Semua 9 komentar

Karena penasaran, mengapa Anda membuat instance dua kali? Apakah Anda dalam tampilan seluler atau sesuatu di mana contoh pertama di viewport diganti dengan tampilan lain, dan ketika pengguna kembali ke tampilan pertama itu, Anda mendapatkan ikatan ganda?

Sesuatu seperti itu. Saya memiliki tampilan beranda, yang akan memanggil titik akhir yang berbeda jika pengguna masuk atau tidak. Binding acara adalah untuk tombol login / logout. Kedua tampilan dipakai tetapi hanya satu yang dirender pada saat itu. Ketika mereka masuk atau keluar, saya akan beralih ke tampilan yang sama tetapi dalam mode yang berbeda. Semoga itu cukup jelas.

Masih belum sepenuhnya jelas bagi saya, mengapa Anda memiliki kedua pandangan yang dipakai pada saat yang sama. Memiliki keduanya mengikat elemen yang sudah ada sebelumnya di dom berarti akan ada peristiwa ganda. Ini sebenarnya bukan bug, tetapi hanya cara kerja acara dan khususnya delegasi acara.

Jika Anda membuat instance tampilan pada elemen yang sudah ada sebelumnya, Anda perlu secara khusus melepaskan ikatan peristiwa tersebut atau mereka akan tetap ada hingga simpul elemen itu sendiri dihapus dari dom.

Yah, sepertinya ide yang bagus untuk membuat instance kedua tampilan selama inisialisasi, mengikat keduanya ke elemen root yang sama di DOM, lalu merender yang satu atau yang lain sesuai dengan mode login dan menggantinya dengan elemen lain saat merender. Saya kira ada cara yang lebih baik untuk melakukannya, dari komentar Anda.

Saya akan membuat instance tampilan saat Anda membutuhkannya. Jika tampilan tidak digunakan, tidak perlu memilikinya untuk menghabiskan memori dan berpotensi menimbulkan efek samping seperti yang Anda lihat.

Saya cenderung tidak menggunakan pola ini:

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

view = new View;
view.render();

tapi sebaliknya saya cenderung menggunakan pola ini, tepatnya untuk menghindari pandangan zombie yang mengakibatkan duplikasi acara

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

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

Satu-satunya lokasi di mana saya akan menggunakan pola pertama Anda, adalah di tampilan Chrome Aplikasi yang membuat GUI:

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

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

begitu juga dengan apa yang @vincentbriglia katakan tentang tidak mendefinisikan el dan membiarkan tampilan menghasilkan elemennya sendiri. Saya melakukan itu 95% dari waktu juga. Namun jika Anda ingin mendefinisikan el dan membersihkan peristiwa saat melepas, Anda dapat menentukan Anda memiliki Backbone.View.destroy() metode dengan .off() untuk setiap sesuai on() dan setiap acara di events: {}

Misalnya:

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

Terima kasih, @malandrew dan @vincentbriglia , itu sangat membantu.

Hanya untuk memperbarui ini untuk anak cucu... Saya menambahkan metode penghancuran ke kelas Tampilan yang terlihat seperti ini

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

Lalu saya hanya menghancurkan tampilan saat ini (State.view) setiap kali saya instantiate().

Apakah halaman ini membantu?
0 / 5 - 0 peringkat