35

我使用 require 将我的视图和路由器分成单独的文件。然后我有一个 main.js 文件来实例化路由器,并呈现我的默认视图。

我的路由器有视图('View/:id')和编辑('Edit/:id')作为路由。在 main.js 中,当我实例化路由器时,我可以硬编码 router.navigate('View/1', true) 并且导航工作正常。在我的视图文件中,当我单击编辑链接时,我想调用 router.navigate('View/' + id, true),但我不确定我应该如何执行此操作。

我已经成功调用 Backbone.history.navigate('View/' + id, true),但我觉得我不应该依赖全局 Backbone 对象。

我尝试将 ({ router: appRouter }) 传递给我的视图,以便我可以使用 this.options.router.navigate(),但这对我不起作用。

如果您好奇,这里有一堆来自我的应用程序的代码:

路由器:

define(['./View', './Edit'], function (View, Edit) {
    return Backbone.Router.extend({
        routes: {
            'View/:id': 'view',
            'Edit/:id': 'edit'
        },

        view: function (id) {
            var model = this.collection.get(id);
            var view = new View({ model: model });
            view.render();
        },

        edit: function (id) {
            var model = this.collection.get(id);
            var edit = new Edit({ model: model });
            edit.render();
        }
    });
});

看法:

define(function () {
    return Backbone.View.extend({
        template: Handlebars.compile($('#template').html()),

        events: {
            'click .edit': 'edit'
        },

        render: function () {
            //Create and insert the cover letter view
            $(this.el).html(this.template(this.model.toJSON()));
            $('#View').html(this.el);

            return this;
        },

        edit: function () {
            Backbone.history.navigate('Edit/' + this.model.id, true); 
        },
    });
});
4

8 回答 8

32

如果其他人像我一样在寻找解决这个问题的方法,我会发布我最终做的事情。如果您使用的是样板骨干.js,那么您将initialize()router.js. 我修改了我的initialize()函数,如下所示:

initialize = function () {
  var app_router;
  app_router = new AppRouter();

  // Extend the View class to include a navigation method goTo
  Backbone.View.goTo = function (loc) {
    app_router.navigate(loc, true);
  };

  Backbone.history.start();
};

由于backbone.js 的特殊继承风格,这允许我MyView.goTo(location);从我的任何视图中调用。

于 2012-03-02T05:02:05.040 回答
20

与几乎所有 Backbone 问题一样,有很多方法可以处理这个问题。我在当前项目中使用它的方法是将所有内容放在全局自定义命名空间中,并使用它来传递必要的引用:

var MyNamespace = {};

MyNamespace.init = function() {
    MyNamespace.appView = new MyAppView();
    MyNamespace.router = new MyRouter();
    // etc
}

然后可以MyNamespace.router根据需要引用视图。但看起来这不起作用/不鼓励使用 require.js,所以这里有一些其他选项:

  • 永远不要显式调用路由器 - 相反,更改路由器侦听的全局状态对象。这实际上是我在当前项目中所做的事情 - 有关更多详细信息,请参阅此回复

  • 将路由器附加到您的顶级视图,通常称为AppView,使其全局可访问,并使用AppView.router.navigate().

  • 制作另一个模块,提供一个内部navigate调用的实用函数Backbone.history.navigate()。这与您正在做的事情并没有太大区别,但它会使其更加模块化,并让您无法一直使用全局引用。这也允许您更改内部实现。

于 2011-10-13T17:33:12.680 回答
8

你可以用老式的方式来做 window.location.hash :)

window.location.hash = "Edit/1"

如果您不需要明确的路线,这是一个替代解决方案。当您的应用程序启动时,创建一个扩展主干事件的对象

window.EventDispatcher = _.extend({}, Backbone.Events);

然后在你的应用程序中的任何地方你都可以监听事件

EventDispatcher.bind("mymodel:edit", this.editHandler, this);

并且还可以从任何地方发送事件,data以下是您想要发送的任何参数

EventDispatcher.trigger("mymodel:edit", data);
于 2011-10-13T17:11:25.457 回答
5

对我来说,带有 goTo 功能的解决方案略有改变

 Backbone.View.prototype.goTo = function (loc) {
      appRouter.navigate(loc, true);
    };
于 2012-04-20T05:45:47.690 回答
3

我知道这个问题很老,但我想知道你为什么不使用 require.js 来获取路由器:

define(['./PathToRouter', ], function (router) {
    return Backbone.View.extend({
        template: Handlebars.compile($('#template').html()),

        events: {
            'click .edit': 'edit'
        },

        render: function () {
            //Create and insert the cover letter view
            $(this.el).html(this.template(this.model.toJSON()));
            $('#View').html(this.el);

            return this;
        },

        edit: function () {
            router.navigate('Edit/' + this.model.id, true);
        }
    });
});
于 2012-10-24T15:49:53.503 回答
2

这种方法怎么样?由于骨干网在其所有 4 个组件中实现了模板模式,只需稍加设计,您就可以通过应用程序的路由器为每个视图提供一个简单的导航机制,而无需进行任何循环引用(这是我在其他类似帖子中看到的,但是尽量避免)。

路由器组件,与其他路由器示例没有太大区别:

define('Router', ['backbone', ... ],
        function (Backbone, ...) {

            var MyRouter = Backbone.Router.extend({
                routes: {
                    'viewA': 'viewA',
                    'viewB': 'viewB'
                },

                initialize: function () {
                    ...
                };
            },
            viewA: function () {
                ...
            },

            viewB: function () {
                ...
            }
});

return MyRouter;
});

应用程序,创建路由器实例并触发传递此实例的第一个视图:

define('App', ['backbone', ...
], function (Backbone, ...) {

    function initialize() {

        //route creation
        if (!this.routes)
            routes = new Router(this); 
        //backbone history start
        Backbone.history.start();

        //ViewA navigation, bigbang
        if (!this.viewA)
            this.viewA = new ViewA({router: this.routes});
        this.viewA.render();
    }

    return {
        initialize: initialize
    };
});

BaseView,所有视图的基本构造函数定义以及导航方法:

define('BaseView', ['jquery', 'underscore',  'backbone', ...
], function ($, _, Backbone, ...) {
    var BaseView;

    BaseView = Backbone.View.extend({
        id: '...',

        constructor: function (options) {
            this.router = options.router;
            this.model = options.model;
            Backbone.View.prototype.constructor.call(this);
        },
        initialize: function () {
            this.template = _.template(tpl);
        },

        events: {

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

            return this;
        },
        //Provides transparent navigation between views throught the backbonejs
        //route mechanism
        navigate: function(pageId)
        {
            this.router.navigate(pageId, {trigger: true});
        }
    });

    return BaseView;
});

一个 View 实例,每个视图都从基础视图而不是主干延伸,并继承基础行为:

define('ViewA', ['jquery', 'underscore',  'backbone', 'BaseView'
], function ($, _, Backbone, BaseView) {
    var ViewA;

    ViewA = BaseView.extend({
        id: '...',

        constructor: function (options) {
            this._super("constructor");
        },

        ...
        foo: function()
        {
            ...

            this.navigate("viewB");
        }
    });

    return ViewA;
});

它对我有用,也可以在其他项目中重用。

于 2013-01-16T02:32:44.700 回答
1

对我来说,我像这样向主应用程序添加了一个对象;

define(['jquery','underscore','backbone','views/personView','views/peopleView','views/textView'],function($,_,backbone,PersonView,PeopleView,TitleView){

    var Router = Backbone.Router.extend({
           routes:{
               '':'home',
               'edit/:id':'editPerson',
               'new':'editPerson',
               'delete/:id':'deletePerson'
               }
            })

              var initialize = function(){

                 var router  = new Router();

                 window.app = {
                     router:router
                     }

        router.on('route:home',function(){


    })

            //enable routing using '#'[hashtag] navigation
        Backbone.history.start();

            };

            return {
            initialize:initialize
            };

});

在您的视图中,您可以说 windows.app.router.navigate({'',trigger:true}) 。不知道在这种情况下全局范围界定是否是好的做法,但它对我有用。

于 2013-01-16T10:42:52.867 回答
0

我有一个用于路由 AMD 模块的新解决方案。

RequireJS 路由器https://github.com/erikringsmuth/requirejs-router

这采用了在您导航到每个页面时延迟加载 AMD 模块的方法。使用 Backbone 路由器,您需要预先要求所有视图作为依赖项。这会在第一页加载时加载您的所有应用程序 Javascript。当您导航到每个路由时,RequireJS 路由器会延迟加载模块。

用于运行您的应用的 main.js 示例

define([], function() {
  'use strict';

  // Configure require.js paths and shims
  require.config({
    paths: {
      'text': 'bower_components/requirejs-text/text',
      'router': 'bower_components/requirejs-router/router'
    }
  });

  // Load the router and your layout
  require(['router', 'js/layout/layoutView'], function(router, LayoutView) {
    var layoutView = new LayoutView();
    // The layout's render method should draw the header, footer, and an empty main-content section
    // then load the content section.
    // render: function() {
    //   this.$el.html(this.template({model: this.model}));
    //   router.loadCurrentRoute();
    // }

    // Configure the router
    router
      .registerRoutes({
        home: {path: '/', moduleId: 'home/homeView'},
        order: {path: '/order', moduleId: 'order/orderView'},
        notFound: {path: '*', moduleId: 'notFound/notFoundView'}
      })
      .on('statechange', function() {
        // Render the layout before loading the current route's module
        layoutView.render.call(layoutView);
      })
      .on('routeload', function(module, routeArguments) {
        // Attach the content view to the layoutView's main-content section
        layoutView.$('#main-content').replaceWith(new module(routeArguments).render().el);
      })
      .init({
        // We're manually calling loadCurrentRoute() from layoutView.render()
        loadCurrentRouteOnStateChange: false
      });
  );
);
于 2014-02-19T19:54:31.083 回答