最好直接从父级调用子视图方法,还是通过启动触发器?

时间:2013-08-19 16:27:52

标签: marionette

我有一个复杂的Backbone / Marionette应用程序,我经常向父元素发泄。当我需要从父元素中触发孩子的事情时,我有点不清楚我应该如何做到这一点。最容易做的就是从父母那里调用孩子的方法,但是,我想知道在这种情况下我是否“作弊”(并且可能导致内存泄漏问题或其他什么?)我很好奇“正确的“方式。

Here's a jsfiddle of an extremely simplified contrived version of my code.以及a gist of the same contrived example in a require based app

<header>
    <h4>A subview/view trigger event loop playground</h4>
    <p>Open your console and then click the button</p>
</header>

<article id="main">
</article>

<script type="text/html" id="MySubView">
    <button type="button" id="button">Click Me</button>
</script>

<script type="text/html" id="MyView">
    <div id="myRegion"></div>
</script>


<script>
var app = new Marionette.Application();

app.addRegions({
    "mainRegion": "#main" 
});

app.module("SampleModule", function(Mod, App, Backbone, Marionette, $, _){

    var MySubView = Marionette.ItemView.extend({
        template: '#MySubView',
        events: {
            'click #button': 'sendClick'
        },

        triggers: {
            'afterClick': 'afterClick'
        },

        initialize: function initialize(){
            this.on('afterClick', this.afterClick);
        },

        sendClick: function(e) {
            e.preventDefault();
            console.log('Good... Use your ventful capabilities boy...');
            //trigger some method in the parent...
            this.trigger('processClick');
        },

        afterClick: function(who) {
            console.log("I've been waiting for you... The circle is now complete. When I left you I was the but the sender, now I am the receiver...", who);
        }
    });

    var MyView = Marionette.Layout.extend({
        template: '#MyView',
        views: {},
        regions: {
            myRegion: '#myRegion'
        },

        onShow: function onShow(){
            this.views.mySubView = new MySubView({ model: this.model }).on('processClick', this.sendBackClick, this);
            this.myRegion.show(this.views.mySubView);
        },

        sendBackClick: function(){
            //do some stuff, then, let the child know you're done...
            console.log('heh heh heh heh.... Goood, goooood! Your triggers have made you powerful. Now, fulfil your parents destiny and take the event at my side!!!');
            //use trigger?
            this.views.mySubView.trigger('afterClick', 'from trigger');
            //call method directly?
            this.views.mySubView.afterClick('called directly');
        }
    });


    var Controller = Marionette.Controller.extend({

        initialize: function(options){
            this.region = options.region
        },

        show: function(){
            var mainView = new MyView({ model: new Backbone.Model({'prop':'value'}) });

            this.region.show(mainView);
        }
    });


    Mod.addInitializer(function(){
        Mod.controller = new Controller({
            region: app.mainRegion
        });
        Mod.controller.show();
    });
});

app.start();
</script>

顺便说一句:注意我在父母身上使用'view'属性来跟踪它的孩子。如果有更好的方法可以做到这一点,或者为什么那么错,我很乐意听到它。

1 个答案:

答案 0 :(得分:2)

有些事情可能会或可能不会回答你的问题:

首先,在您的设计示例中,很明显您希望孩子知道父母已经处理过“点击”,但在现实世界中,我猜这可能实际上并不是相关的信息。也许孩子应该全神贯注地听别的东西?例如,您的布局和子视图碰巧共享模型。我将进行一次飞跃并猜测点击事件实际上是为了启动该模型的某些处理。如果是这种情况,孩子真正想知道的是在模型上触发的事件(内置或自定义)。通过这种方式,子视图可以适当地响应事件,即使它不是来自首先的点击(对我来说似乎有一天可能有多条路径)。当然,这是在做出很多假设。如果它不是作为此事件中心的模型,它仍然可以是除子视图之外的其他东西 - app.vent?父布局本身?一切都取决于确切的用例。

其次,在定义布局时注意创建视图对象。这将是您实例化的布局的各个实例之间的共享引用。这可能是你想要的,但是(再次假设)我猜它不是。