如何在Backbone View层次结构中“冒泡”事件?

时间:2021-08-11 08:24:23

I have a backbone app with a view structure that looks like the following - note that I've removed implementations, models, collections, etc. for brevity:

我有一个骨干应用程序,其视图结构如下所示 - 请注意,为了简洁,我删除了实现,模型,集合等:

NewsListView = Backbone.View.extend({

    el: $('li#newspane'),

    // This is what I would like to be able to do
    // events: { 'filtered': 'reset' }

    initialize: function() {
        _.bindAll(this);
    },

    render: function() {
    },

    reset: function(){
    }

});

FilterView = Backbone.View.extend({

    el: $('li.filter'),

    initialize: function() {
    },

    render: function() {
    },

    toggleFilter: function() {
    }

});

AllView = Backbone.View.extend({

    initialize: function() {

        this.newsListView = new NewsListView();
        this.filterView = new FilterView();

    }

});

Essentially, whenever the FilterView's toggleFilter() function is called, I would like to fire off an event called filtered or something like that that is then caught by the NewsListView, which then calls its reset() function. Without passing a reference of a NewsListView object to my FilterView, I'm not sure how to send it an event. Any ideas?

本质上,每当调用FilterView的toggleFilter()函数时,我想触发一个名为filtered的事件或类似的事件,然后由NewsListView捕获,然后调用其reset()函数。没有将NewsListView对象的引用传递给我的FilterView,我不知道如何向它发送事件。有任何想法吗?

6 个解决方案

#1


5  

You're on the right track. It sounds like what you need is a global event dispatcher. There a decent article and example here: http://www.michikono.com/2012/01/11/adding-a-centralized-event-dispatcher-on-backbone-js/

你走在正确的轨道上。听起来你需要的是全球事件调度员。这里有一篇不错的文章和例子:http://www.michikono.com/2012/01/11/adding-a-centralized-event-dispatcher-on-backbone-js/

#2


3  

You might be able to do this using the already available functionality of jquery events and the backbone events property.

您可以使用jquery事件和骨干事件属性的已有功能来执行此操作。

For example, instead of doing this from inside your subview:

例如,而不是从子视图中执行此操作:

this.trigger("yourevent", this);

do this instead:

改为:

this.$el.trigger("yourevent", this);

Then in any view that is a parent, grandparent, etc of your child view, listen for the event on that view's $el by defining a property on that view's events object:

然后在您的子视图的父视图,祖父视图等的任何视图中,通过在该视图的事件对象上定义属性来侦听该视图的$ el上的事件:

events:{
    "yourevent":"yourhandler"
}

and define the handler on that view as well:

并在该视图上定义处理程序:

yourhandler:function(subview) {
}

So this way, a view doesn't need to know about what descendant views exist, only the type of event it is interested in. If the view originating the event is destroyed, nothing needs to change on the ancestor view. If the ancestor view is destroyed, Backbone will detach the handlers automatically.

所以这样,视图不需要知道后代视图的存在,只知道它感兴趣的事件类型。如果导致事件的视图被破坏,则祖先视图中不需要更改任何内容。如果祖先视图被破坏,Backbone将自动分离处理程序。

Caveat: I haven't actually tried this out yet, so there may be a gotcha in there somewhere.

警告:我还没有真正试过这个,所以在那里可能会有一个问题。

#3


1  

You should check out the Backbone.Courier plugin as bubbling events is a perfect use case:

您应该查看Backbone.Courier插件,因为冒泡事件是一个完美的用例:

https://github.com/dgbeck/backbone.courier

https://github.com/dgbeck/backbone.courier

#4


0  

This problem can be solved using small backbone.js hack. Simply modify Backbone.Events.trigger for passing events to the this.parent

使用small backbone.js hack可以解决这个问题。只需修改Backbone.Events.trigger即可将事件传递给this.parent

if this.parent != null

#5


0  

So, I came up a with a solution - create an object that extends Backbone.Events, and pass it as a parameter to multiple views. This almost feels like message passing between actors, or something. Anyway - I'm posting this as an answer in case anybody else needs a quick solution, but I'm not going to accept the answer. This feels hacky. I'd still like to see a better solution.

所以,我提出了一个解决方案 - 创建一个扩展Backbone.Events的对象,并将其作为参数传递给多个视图。这几乎就像演员之间的消息传递一样。无论如何 - 我发布这个作为答案,以防任何其他人需要快速解决方案,但我不会接受答案。这感觉很糟糕。我仍然希望看到更好的解决方案。

NewsListView = Backbone.View.extend({
    el: $('li#newspane'),

    // Too bad this doesn't work, it'd be really convenient
    // events: { 'filtered': 'reset' }

    initialize: function() {
        _.bindAll(this);
        // but at least this does
        this.options.eventProxy.bind('filtered', this.reset);
    },
    render: function() {},
    reset: function() {}
});

FilterView = Backbone.View.extend({
    el: $('li.filter'),

    initialize: function() {},
    render: function() {},
    toggleFilter: function() {
        this.options.eventProxy.trigger('filtered');
    }
});

AllView = Backbone.View.extend({
    initialize: function() {
        var eventProxy = {};
        _.extend(eventProxy, Backbone.Events);
        this.newsListView = new NewsListView({eventProxy: eventProxy});
        this.filterView = new FilterView({eventProxy: eventProxy});
    }
});

#6


0  

The easiest way I've found to trigger and listen to events is to just use the Backbone object itself. It already has the events functions mixed in to it, so you can just trigger eg:

我发现触发和侦听事件的最简单方法是使用Backbone对象本身。它已经混合了事件函数,所以你可以触发例如:

Backbone.trigger('view:eventname',{extra_thing:whatever, thing2:whatever2});

then, in any other backbone view in your app, you can listen for this event eg:

然后,在您的应用程序的任何其他骨干视图中,您可以监听此事件,例如:

Backbone.on('view:eventname', function(passed_obj) {
    console.log(passed_obj.extra_thing);
});

I'm not exactly sure what the advantage is in not using the Backbone object as your event handler, and instead creating a separate object to do it, but for quick-and-dirty work, the above works fine. HTH!

我不确定不使用Backbone对象作为事件处理程序的优点是什么,而是创建一个单独的对象来执行它,但对于快速和脏的工作,上面的工作正常。 HTH!

NOTE: one disadvantage to this is that every listener will "hear" every single event triggered in this way. Not sure what the big O is on that, but work being careful to not overload your views with lots of this stuff. Again: this is quick and dirty! :)

注意:这样做的一个缺点是每个听众都会“听到”以这种方式触发的每个事件。不确定那个大O是什么,但是要小心不要用大量的东西重载你的观点。再说一遍:这很快又脏! :)

#1


5  

You're on the right track. It sounds like what you need is a global event dispatcher. There a decent article and example here: http://www.michikono.com/2012/01/11/adding-a-centralized-event-dispatcher-on-backbone-js/

你走在正确的轨道上。听起来你需要的是全球事件调度员。这里有一篇不错的文章和例子:http://www.michikono.com/2012/01/11/adding-a-centralized-event-dispatcher-on-backbone-js/

#2


3  

You might be able to do this using the already available functionality of jquery events and the backbone events property.

您可以使用jquery事件和骨干事件属性的已有功能来执行此操作。

For example, instead of doing this from inside your subview:

例如,而不是从子视图中执行此操作:

this.trigger("yourevent", this);

do this instead:

改为:

this.$el.trigger("yourevent", this);

Then in any view that is a parent, grandparent, etc of your child view, listen for the event on that view's $el by defining a property on that view's events object:

然后在您的子视图的父视图,祖父视图等的任何视图中,通过在该视图的事件对象上定义属性来侦听该视图的$ el上的事件:

events:{
    "yourevent":"yourhandler"
}

and define the handler on that view as well:

并在该视图上定义处理程序:

yourhandler:function(subview) {
}

So this way, a view doesn't need to know about what descendant views exist, only the type of event it is interested in. If the view originating the event is destroyed, nothing needs to change on the ancestor view. If the ancestor view is destroyed, Backbone will detach the handlers automatically.

所以这样,视图不需要知道后代视图的存在,只知道它感兴趣的事件类型。如果导致事件的视图被破坏,则祖先视图中不需要更改任何内容。如果祖先视图被破坏,Backbone将自动分离处理程序。

Caveat: I haven't actually tried this out yet, so there may be a gotcha in there somewhere.

警告:我还没有真正试过这个,所以在那里可能会有一个问题。

#3


1  

You should check out the Backbone.Courier plugin as bubbling events is a perfect use case:

您应该查看Backbone.Courier插件,因为冒泡事件是一个完美的用例:

https://github.com/dgbeck/backbone.courier

https://github.com/dgbeck/backbone.courier

#4


0  

This problem can be solved using small backbone.js hack. Simply modify Backbone.Events.trigger for passing events to the this.parent

使用small backbone.js hack可以解决这个问题。只需修改Backbone.Events.trigger即可将事件传递给this.parent

if this.parent != null

#5


0  

So, I came up a with a solution - create an object that extends Backbone.Events, and pass it as a parameter to multiple views. This almost feels like message passing between actors, or something. Anyway - I'm posting this as an answer in case anybody else needs a quick solution, but I'm not going to accept the answer. This feels hacky. I'd still like to see a better solution.

所以,我提出了一个解决方案 - 创建一个扩展Backbone.Events的对象,并将其作为参数传递给多个视图。这几乎就像演员之间的消息传递一样。无论如何 - 我发布这个作为答案,以防任何其他人需要快速解决方案,但我不会接受答案。这感觉很糟糕。我仍然希望看到更好的解决方案。

NewsListView = Backbone.View.extend({
    el: $('li#newspane'),

    // Too bad this doesn't work, it'd be really convenient
    // events: { 'filtered': 'reset' }

    initialize: function() {
        _.bindAll(this);
        // but at least this does
        this.options.eventProxy.bind('filtered', this.reset);
    },
    render: function() {},
    reset: function() {}
});

FilterView = Backbone.View.extend({
    el: $('li.filter'),

    initialize: function() {},
    render: function() {},
    toggleFilter: function() {
        this.options.eventProxy.trigger('filtered');
    }
});

AllView = Backbone.View.extend({
    initialize: function() {
        var eventProxy = {};
        _.extend(eventProxy, Backbone.Events);
        this.newsListView = new NewsListView({eventProxy: eventProxy});
        this.filterView = new FilterView({eventProxy: eventProxy});
    }
});

#6


0  

The easiest way I've found to trigger and listen to events is to just use the Backbone object itself. It already has the events functions mixed in to it, so you can just trigger eg:

我发现触发和侦听事件的最简单方法是使用Backbone对象本身。它已经混合了事件函数,所以你可以触发例如:

Backbone.trigger('view:eventname',{extra_thing:whatever, thing2:whatever2});

then, in any other backbone view in your app, you can listen for this event eg:

然后,在您的应用程序的任何其他骨干视图中,您可以监听此事件,例如:

Backbone.on('view:eventname', function(passed_obj) {
    console.log(passed_obj.extra_thing);
});

I'm not exactly sure what the advantage is in not using the Backbone object as your event handler, and instead creating a separate object to do it, but for quick-and-dirty work, the above works fine. HTH!

我不确定不使用Backbone对象作为事件处理程序的优点是什么,而是创建一个单独的对象来执行它,但对于快速和脏的工作,上面的工作正常。 HTH!

NOTE: one disadvantage to this is that every listener will "hear" every single event triggered in this way. Not sure what the big O is on that, but work being careful to not overload your views with lots of this stuff. Again: this is quick and dirty! :)

注意:这样做的一个缺点是每个听众都会“听到”以这种方式触发的每个事件。不确定那个大O是什么,但是要小心不要用大量的东西重载你的观点。再说一遍:这很快又脏! :)