Maintain a stack of Marionette ItemViews within a Marionette Layout

↘锁芯ラ 提交于 2019-12-06 14:05:28

Use a backbone router to listen to URL change events. Setup routes for each of your views and then have the router call the layout to change the view it's displaying in response to each route. The user could click back or forward any number of times and the app responds accordingly and displays the correct view. Your router might look like:

var Router = Backbone.router.extend({
    routes: {
        'my/route/itemViewA': 'showItemViewA',
        'my/route/itemViewB': 'showItemViewB'
    },

    showItemViewA: function () {
        layout.showItemView('a');
    },

    showItemViewB: function () {
        layout.showItemView('b');
    }
});

Your layout might look something like this:

var Layout = Backbone.Marionette.Layout.extend({

    regions: {
        someRegion: 'my-region-jquery-selector'
    },

    initialize: function () {
        this.createViews();
    },

    createViews: function () {
        this.views = {
            a: new Backbone.Marionette.ItemView,
            b: new Backbone.Marionette.ItemView
        };
    },

    showItemView: function (view) {
        this.someRegion.show(this.views[view]);

        // You might want to do some other stuff here
        // such as call delegateEvents to keep listening
        // to models or collections etc. The current view
        // will be closed but it won't be garbage collected
        // as it's attached to this layout.
    }
});

The method of communication between the router and the layout doesn't have to be a direct call. You could trigger further application-wide events or do anything else you can think of. The router above is very basic but gets the job done. You could create a more intelligent router to use a single route with parameters to determine dynamically which itemView to show.

Every time the user does something that requires changing views, you can update the browser's history by using router.navigate('my/route/itemViewB', {trigger: true});. Also, if you set up your app to only render on history change events then you don't need to set up two mechanisms for rending each view.

I use this pattern in my own apps and it works very well.

@Simon's answer is headed in the correct direction. However, the only way to stop Marionette from closing views is to modify a bit of it's Region code.

var NoCloseRegion = Marionette.Region.extend({
    open: function(view) {
        // Preserve the currentView's events/elements
        if (this.currentView) { this.currentView.$el.detach(); } 

        // Append the new view's el
        this.$el.append(view.el);
    }
});

The, when be sure to specify our new Region class when creating the Layout view

var Layout = Backbone.Marionette.Layout.extend({
    regions: {
        someRegion: {
            selector: 'my-region-jquery-selector',
            regionType: NoCloseRegion
        },
    },
    initialize: function () {
        this.createViews();
    },
    createViews: function () {
        this.views = {
            a: new Backbone.Marionette.ItemView,
            b: new Backbone.Marionette.ItemView
        };
    },
    showItemView: function (name) {
        // Don't `show`, because that'll call `close` on the view
        var view = this.views[name];
        this.someRegion.open(view)
        this.someRegion.attachView(view)
    }
});

Now, instead of calling show which closes the old view, renders the new, and attaches it to the region (and triggers a few events), we can detach the old view, attach the new, and open it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!