Использование маршрутизатора Backbone.js для навигации по представлениям, модульным с require.js - PullRequest
35 голосов
/ 13 октября 2011

Я разделяю мои представления и маршрутизатор на отдельные файлы с помощью 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); 
        },
    });
});

Ответы [ 8 ]

32 голосов
/ 02 марта 2012

В случае, если кто-то еще ищет решение этой проблемы, как я, я публикую то, что я в итоге сделал.Если вы используете шаблон backbone.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); из любого моего представления.*

20 голосов
/ 13 октября 2011

Как и в большинстве случаев с 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() внутри. Это не сильно отличается от того, что вы делаете, но это сделает его немного более модульным и не позволит вам постоянно использовать глобальные ссылки. Это также позволяет изменить внутреннюю реализацию.

8 голосов
/ 13 октября 2011

Вы можете сделать это по старинке с помощью window.location.hash:)

window.location.hash = "Edit/1"

Вот альтернативное решение, если вам не нужны явные маршруты. Когда ваше приложение запускается, создайте объект, который расширяет Backbone Events

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

Тогда в любом месте вашего приложения вы можете слушать события

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

А также из любой точки отправления события, data ниже указаны любые параметры, которые вы хотите отправить для поездки

EventDispatcher.trigger("mymodel:edit", data);
5 голосов
/ 20 апреля 2012

Для меня решение с функцией goTo работало с небольшим изменением

 Backbone.View.prototype.goTo = function (loc) {
      appRouter.navigate(loc, true);
    };
3 голосов
/ 24 октября 2012

Я знаю, что этот вопрос старый, но мне интересно, почему вы не используете 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);
        }
    });
});
2 голосов
/ 16 января 2013

А как насчет этого подхода?Поскольку базовая схема реализует шаблон шаблона во всех его 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;
});

Экземпляр представления, каждое представление расширяется от базового вместо базового и наследует базовое поведение:

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;
});

Это работает для меня, а также его можно использовать в других проектах.

1 голос
/ 16 января 2013

для меня я добавил объект в основное приложение, как это;

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}).Не знаю, является ли глобальная оценка полезной практикой в ​​этом случае, но это сработало для меня.

0 голосов
/ 19 февраля 2014

У меня есть новое решение для маршрутизации модулей AMD.

RequireJS Router 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
      });
  );
);
...