从项目视图到父布局视图的木偶泡沫事件?

时间:2013-05-31 22:47:25

标签: backbone.js marionette backbone-views

我有一个带有区域的布局视图,在该区域中我有一个触发事件的项目视图,但它似乎没有冒泡到布局视图。我做错了什么还是这个设计行为?我假设没有添加itemview前缀,因为父视图不是集合视图?无论哪种方式,事件都不会冒泡到布局视图。

layoutView = Marionette.Layout.extend({
        template: "#layout-template",
        regions: {
            titleRegion: "#job-title-region"
        },
        triggers: {
            "save:clicked" : "onSaveClicked"
        },
        onSaveClicked: function (args) {
            alert('Clicked');
        }
    });

childview = Marionette.ItemView.extend({
        template: "#child-template",
        triggers: {
            "click .js-save": "save:clicked"
        }
    });

更新

看到这个小提琴http://jsfiddle.net/7ATMz/11/我设法得到布局视图来监听子事件,但是我必须在布局视图本身之外连接它并打破封装。我是否可以在布局视图中执行此操作?

谢谢,

乔恩

5 个答案:

答案 0 :(得分:10)

触发器不是那样的:你的布局错误地使用了它们。在给定某种交互(例如点击)的情况下,触发器可以方便地引发事件信号。

您想要的是使用triggerMethod(https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.functions.md#marionettetriggermethod)来触发布局中的功能。请参阅http://jsfiddle.net/ZxEa5/基本上,您希望在show函数中使用此功能:

childView.on("btn:clicked", function(){
  layout.triggerMethod("childView:btn:clicked"); 
});

在你的布局中:

onChildViewBtnClicked: function(){
   https://leanpub.com/marionette-gentle-introduction
});

事件冒泡只能通过集合?复合视图自动发生,因为它们与项目视图紧密相关。如果您希望布局监视其子视图之一,则需要自行设置。

无耻插件:如果您想了解更多关于如何使用Marionette构建和清理代码的信息,您可以查看我的书(https://leanpub.com/marionette-gentle-introduction),其中介绍了此类概念(及其应用程序)更多细节。

答案 1 :(得分:7)

我不确定何时引入此Marionette功能,但更简单的解决方案是使用childEvents哈希:http://marionettejs.com/docs/v2.4.1/marionette.layoutview.html#layoutview-childevents

...
childEvents: {
  "save:clicked" : "onSaveClicked"
},
...

你也可以直接将子事件绑定到LayoutView之外的函数,如果它更有意义,就像这样:

layout.on('childview:save:clicked', function(childView) {
  alert('clicked');
}

答案 2 :(得分:4)

我建议使用Backbone.Courier满足此类需求:https://github.com/rotundasoftware/backbone.courier

答案 3 :(得分:1)

我针对类似问题实施了如下解决方案。首先,我在Marionette.View原型中写了一个新方法:

Marionette.View.prototype.bubbleMethod = function () {
    var args = _.toArray(arguments)
    var event = args.shift()
    var bubble = event + ':bubble'
    this.triggerMethod.apply(this, [ event ].concat(args))
    this.triggerMethod.apply(this, [ bubble ].concat(args))
}

这将从Marionette两次调用常规triggerMethod:一次是您的事件名称,因为它是打算处理的,另一个可以通过专门的视图轻松识别,被指定为冒泡事件。

然后你将需要这样的专业视图和冒泡事件,这些事件应该被冒泡。您必须小心不要代表其他视图发送close(或任何木偶事件)等事件,因为这会导致区域和视图中的各种不可预测的行为。 :bubble后缀可让您轻松识别泡泡的含义。冒泡的视图可能如下所示:

var BubblingLayout = Marionette.Layout.extend({
    handleBubbles: function (view) {
        var bubble = /:bubble$/
        this.listenTo(view, 'all', function () {
            var args = _.toArray(arguments)
            var event = args.shift()
            if (event.match(bubble)) {
                event = event.replace(bubble, '')
                this.bubbleMethod.apply(this, [ event ].concat(args))
            }
        }, this)
    }
})

您需要确保的最后一件事是能够跨区域鼓泡事件(对于使用自定义区域管理器的布局和模块)。这可以通过区域中的show事件调度来处理,如下所示:

var BubblingLayout = Marionette.Layout.extend({
    regions: {
        sidebar: '#sidebar'
    },
    initialize: function () {
        this.sidebar.on('show', this.handleBubbles, this)
    },
    handleBubbles: function (view) {
        var bubble = /:bubble$/
        this.listenTo(view, 'all', function () {
            var args = _.toArray(arguments)
            var event = args.shift()
            if (event.match(bubble)) {
                event = event.replace(bubble, '')
                this.bubbleMethod.apply(this, [ event ].concat(args))
            }
        }, this)
    }
})

最后一部分是让一些东西真正冒出来,这可以通过新的bubbleMethod方法轻松处理:

var MyView = Marionette.ItemView.extend({
    events: {
        'click': 'clickHandler'
    },
    clickHandler: function (ev) {
        // do some stuff, then bubble something else
        this.bubbleMethod('stuff:done')
    }
})

var BubblingLayout = Marionette.Layout.extend({
    regions: {
        sidebar: '#sidebar'
    },
    initialize: function () {
        this.sidebar.on('show', this.handleBubbles, this)
    },
    onRender: function () {
        var view = new MyView()
        this.sidebar.show(view)
    },
    handleBubbles: function (view) {
        var bubble = /:bubble$/
        this.listenTo(view, 'all', function () {
            var args = _.toArray(arguments)
            var event = args.shift()
            if (event.match(bubble)) {
                event = event.replace(bubble, '')
                this.bubbleMethod.apply(this, [ event ].concat(args))
            }
        }, this)
    }
})

现在,您可以在代码中的任何位置处理冒泡事件,您可以在其中访问BubblingLayout的实例。

答案 4 :(得分:0)

为什么不允许click事件冒泡DOM层次结构并在Layout视图中处理它?这样的事情(小提琴here):

var MainView = Marionette.Layout.extend({
    template: "#layout-template",
    regions: {
        childRegion: "#childRegion"   
    },
    events: {
        'click #btn': 'handleButtonClick'   
    },
    handleButtonClick: function() {
       alert('btn clicked in child region and bubbled up to layout');
    }
});

var ChildView = Marionette.ItemView.extend({
    template: "#child-template"
    /*
    triggers: {
        "click #btn": "btn:clicked"   
    }*/
});