在.html([content])之后仍然附加了Backbone 1.0 js事件

时间:2013-06-14 17:25:20

标签: backbone.js backbone-events

我遇到的问题是点击事件不断堆积(更改视图后仍然附加)。我通过只有一个视图实例(如下所示)解决了这个问题。我认为当标记改变时,脊柱会消除事件。我对其他观点没有这个问题。

BROKEN CODE:随着更多视图的创建,点击事件会继续堆积在loadPlayerCard上。

//Player Thumb View
PgaPlayersApp.PlayerThumbView = Backbone.View.extend({
    events: {
        'click': 'loadPlayerCard'
    },
    tagName: 'li',
    template: _.template( $('#player_thumb').html()),    
    render: function()
    {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    loadPlayerCard: function()
    {
        new PlayerCardView({model: this.model}).render();
        return false;
    }
});

//Router
var Router = Backbone.Router.extend({
    routes:{
      '': 'loadPlayers'
    },

    loadPlayers: function()
    {
        PgaPlayersApp.Players.fetch({reset: true, success: function()
        {
            //When players is first fetched, we want to render the first player into the card area
            new PlayerCardView({model: PgaPlayersApp.Players.first()}).render();

        }});
    }
});

PgaPlayersApp.Router = new Router();
Backbone.history.start();

固定代码:解决问题的代码:

PgaPlayersApp.CurrentPlayerCard = new PlayerCardView();

//Player Thumb View
PgaPlayersApp.PlayerThumbView = Backbone.View.extend({
    events: {
        'click': 'loadPlayerCard'
    },
    tagName: 'li',
    template: _.template( $('#player_thumb').html()),    
    render: function()
    {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    loadPlayerCard: function()
    {
        PgaPlayersApp.CurrentPlayerCard.model = this.model;
        PgaPlayersApp.CurrentPlayerCard.render();
        return false;
    }
});

//Router
var Router = Backbone.Router.extend({
    routes:{
      '': 'loadPlayers'
    },

    loadPlayers: function()
    {
        PgaPlayersApp.Players.fetch({reset: true, success: function()
        {
            //When players is first fetched, we want to render the first player into the card area
            PgaPlayersApp.CurrentPlayerCard.model = PgaPlayersApp.Players.first();
            PgaPlayersApp.CurrentPlayerCard.render();
        }});
    }
});

PgaPlayersApp.Router = new Router();
Backbone.history.start();

PlayerCardView(供参考):

var PlayerCardView = PgaPlayersApp.PlayerCardView = Backbone.View.extend({
    events: {
        'click': 'flipCard'
    },
    el: '#pga_player_card',
    template: _.template( $('#player_card').html()),
    render: function()
    {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    flipCard: function()
    {
        this.$("#player_card_container").toggleClass('flip');
    }
});

1 个答案:

答案 0 :(得分:0)

在路由器中,您不断创建新的PlayerCardView

new PlayerCardView({model: PgaPlayersApp.Players.first()}).render();

所有这些观点都完全相同el

el: '#pga_player_card'

所以你不断创建新的PlayerCardView,每个人都绑定到#pga_player_card

每次执行此操作时,都会将全新视图绑定到完全相同的DOM元素,并且每个视图都会调用delegateEvents来绑定事件处理程序。请注意,delegateEvents绑定到eljQuery's html method

  在使用新内容替换这些元素之前,

从子元素中删除其他构造(如数据和事件处理程序)。

因此htmlel不执行任何操作,但它会从子元素中删除事件处理程序。请考虑使用<div id="d"></div>

这个简单示例
$('#d').on('click', function() {
    console.log('Before .html');
});
$('#d').html('<p>Where is pancakes house?</p>');
$('#d').on('click', function() {
    console.log('After .html');
});

如果您再点击#d,您将在控制台中看到前后消息。

  

演示:http://jsfiddle.net/ambiguous/ftJtS/

这个简单的例子或多或少等同于你正在做的事情。

如果你有更好的时间:

  1. 将视图置于 #pga_player_card内,让路由器执行$('#pga_player_card').append(view.render().el)
  2. 在添加新视图之前,先跟踪已经存在的视图和view.remove()
  3. 避免尝试为多个视图实例重用DOM元素,避免尝试重用视图,这也不值得麻烦。