1

我正在编写我的第一个 Backbone.js 应用程序,但在找出最佳编程方式时遇到了一些麻烦。我有两个主要观点:

  1. 显示我所有模型的索引。
  2. 显示用于编辑的特定模型。

但是#2有许多不同的“模块”,比如我可以编辑“新闻”部分或“关于”部分等......所有这些模块都在导航栏中。

当我显示视图#1(所有模型的索引)时,该导航栏被隐藏。它在视图#2(特定模型)中可见,以便在不同模块之间导航。

我有这样的路线设置:

routes: {
    '', 'index',
    'communities': 'index',
    'communities/:id': 'main',
    'communities/:id/news', 'news',
    'communities/:id/about', 'about'
},

所以我的问题是,当调用“新闻”或“关于”操作时,我是否在每个方法中添加导航栏?这不是多余的吗?我将拥有 8-10 个不同的模块,每次添加导航栏似乎非常重复。有没有更好的办法?我唯一希望隐藏导航栏的时候是在显示索引时。

4

2 回答 2

6

当我创建我的第一个有点复杂的 Backbone 应用程序时,我遇到了同样的问题。除了您对冗余代码的关注之外,我还担心绑定到我的导航栏的事件可能不会随着导航栏的更改而解除绑定。为了解决这个问题,我最终创建了一个视图层次结构,一个管理器视图管理整个导航栏,并为我想要显示的每种类型的导航菜单提供单独的视图,这些视图将传递给管理器视图以呈现给页。

这是我的实现示例。

在我们开始之前,这是close我添加到 BackboneView原型中的一个函数,它取消绑定事件并删除视图

Backbone.View.prototype.close = function() {
    if(this.beforeClose) { this.beforeClose(); }
    this.remove();
    this.unbind();
}

首先,这是我的Manager View。它的render功能会关闭当前显示的任何菜单,并将其替换为传递给它的菜单view。虽然有点多余,但我创建了一个显式empty函数以使我的路由器代码更易于理解。

var App.Views.SubNavBar = Backbone.View.extend({

    currentView: null,

    el: '#subnav-wrap',

    render: function(view) {
        if(this.currentView) { this.currentView.close(); }
        this.currentView = view;
        this.$el.html(view.el);
    },

    empty: function() {
        if(this.currentView) { this.currentView.close(); }
        this.currentView = null;
    }

});

其次,这是我所有特定导航菜单视图都扩展的基本视图。由于它们都将具有相同tagName的 , className,idinitializeandrender功能,因此可以将重复降至最低

var App.Views.SubNavBase = Backbone.View.extend({

    tagName: 'ul',

    className: 'nav nav-pills',

    id: 'subnav',

    template: _.template($('#tmpl-subnav').html(),

    initialize: function() {
        if(this.setLinks) { this.setLinks(); }
        this.render();
    },

    render: function() {
        this.$el.html(this.template({links:this.links}));
        return this;
    }

});

以下是特定导航菜单的视图示例。您可以看到我需要做的就是定义我希望出现在菜单中的链接。当我实例化这个视图时,函数SubNavBase将处理用所需的 HTML 填充视图。请注意,我还附加了一些事件到此视图。

var App.Views.Projects.DisplayNav = App.Views.SubNavBase.extend({

    setLinks: function() {
        this.links = {
            'Edit Project': {
                icon: 'edit',
                class: 'menu-edit',
                href: '#projects/'+this.model.get('id')+'/edit'
            },
            'Add Group': {
                icon: 'plus',
                class: 'menu-add-group',
                href: '#projects/'+this.model.get('id')+'/groups/new'
            },
            'Delete Project': {
                icon: 'trash',
                class: 'menu-delete',
                href: '#'
            }
        }
    },

    events: {
        'click a.menu-delete' : 'delete'
    },

    delete: function(e) {
        e.preventDefault();
        // here goes my code to delete a project model
    }

});

现在,这是我用来将上面的链接对象转换为<li>元素列表的 underscore.js 模板。请注意,我使用<@而不是<%我的模板,因为这是一个 rails 应用程序并且 rails 已经使用<%

<script type="text/template" id="tmpl-subnav">
    <@ _.each(links,function(link, title) { @>
    <li>
        <a href="<@= link.href @>" class="<@= link.class @>">
            <i class="icon-<@= link.icon @>"></i>
            <@= link.title @>
        </a>
    </li>
    <@ }); @>
</script>

最后,总而言之,这是一个Router创建和呈现导航菜单的示例函数。发生的步骤如下:

  • App.Views.Projects.DisplayNav传递一个模型并this.el用相应的 HTML 填充它,由 underscore.js 模板确定
  • App.SubNavBarrender使用新的菜单视图调用其函数
  • App.SubNavBar检查导航栏中当前是否有另一个菜单;如果是这样,它会调用其视图的close()函数
  • App.SubNavBarfinally 将传递的视图的 HTML 附加到自身,维护对视图的引用以供以后使用

我只包含了路由器代码的相关部分

var App.Routers.Projects = Backbone.Router.extend({
    routes: {
        'projects/:id' : 'display'
    },

    display: function(id) {
        var p = projects.get(id);
        var subnav = new App.Views.Projects.DisplayNav({model:p})
        App.SubNavManager.render(subnav);  // App.SubNavManager is an instance of App.Views.SubNavBar
    }
});

所有这一切的好处是我现在可以将事件附加到我的菜单特定视图,如果用户导航到不同的内容并且菜单发生更改,管理器视图将负责解除它们的绑定。

当然,您可以使用许多其他模式来处理导航菜单,但希望这对您有所帮助。

于 2012-07-03T14:04:42.257 回答
1

试试这个:

routes: {
    '', 'index',
    'communities': 'index',
    'communities/:id': 'main',
    'communities/:id/:section': 'openSection'
},
openSection : function(id, section){
    if( section ){
        this.addNavigationBar();
    }
    switch( section ){
        case 'news' :
             this.news();
             break;
        case 'about' :
             this.about();
             break;
        default: 
             this.main();
    }
}

如果您的网址包含一个部分,您将添加导航栏,然后像您一样调用您的正常方法。

于 2012-07-03T13:19:58.933 回答