Переходы страниц с RequireJS и Backbone.js

Я разрабатываю мобильное приложение с использованием RequireJS и Backbone.js. Я хотел бы указать переход с одной страницы на другую, добавив атрибуты data-transition и data-direction к каждому якорю (точно так же, как с jQuery Mobile):

<a href="#home" data-transition="slide" data-direction="left">Go to the home page</a>

Все мои представления расширяют базовый вид, который прикрепляет обработчик кликов к привязкам и ловит значения этих атрибутов:

define([
    'zepto',
    'lodash',
    'backbone'
], function ($, _, Backbone) {
    'use strict';

    BaseView = Backbone.View.extend({
        events: {
            'click a': 'navigate'
        },
        navigate: function (e) {
            e.preventDefault();

            var href = $(e.currentTarget).attr('href'),
                transition = $(e.currentTarget).attr('data-transition'),
                direction = $(e.currentTarget).attr('data-direction');

            Backbone.history.navigate(href, true);
        }
    });
});

Моя проблема в том, что я не знаю, как передать эти значения обработчикам маршрутов моего маршрутизатора, которые определены как еще один модуль:

define([
    'zepto',
    'lodash',
    'backbone'
], function ($, _, Backbone) {
    'use strict';

    var Router = Backbone.Thumb.Router.extend({
        routes: {
            '': 'home'
        }
    });

    var initialize = function () {
        var router = new Router();

        router.on('route:home', function () {
            require(['views/home'], function (HomeView) {
                var homeView = new HomeView();

                // Get the data-transition and data-direction attributes
                // ​​of the clicked anchor here:

                // var transition = ???,
                //     direction = ???;

                router.animate(homeView.render().$el, transition, direction);
            });
        });

        Backbone.history.start();
    };

    return {
        initialize: initialize
    };
});

Кто-нибудь знает хорошее решение этой проблемы?

Спасибо вам заблаговременно!:-) С уважением,

Дэвид

Ответ 1

События

Как вы знаете, Backbone.js - это платформа, управляемая событиями. Каждый объект, который он определяет, наследует от объекта Backbone.Events и может отправлять и получать сообщения о событиях. Это означает, что сам маршрутизатор может прослушивать события.

Использование глобальных сообщений

Начиная с версии 0.9.2, сам глобальный объект Backbone может использоваться как mediator для глобального обмена сообщениями. Поскольку объект представления в приложении может не знать о маршрутизаторе (особенно это верно при использовании модулей requireJS), можно включить обмен данными между этими объектами с помощью посредника.

Пример маршрутизатора, прослушивающего глобальное событие:

var router = Backbone.Router.extend({
  initialize: function() {
    this.listenTo( Backbone, 'page-transition', this.animate );
  },
  animate: function( href, transition, direction ) {
    // Do something interesting with this
  }
});

Что здесь hapenning?

  • Маршрутизатор регистрирует свою собственную функцию animate в стеке Backbone.events['page-transition'] при ее создании.
  • Когда объект Backbone запускает событие page-transition, он вызывает функцию router.animate с аргументами, предоставленными триггером события.

Где я могу вызвать событие?

От в любом месте в приложении.

Как мне инициировать событие?

Вот пример, основанный на коде из вашего вопроса:

BaseView = Backbone.View.extend({
  events: {
    'click a': 'transition'
  },
  transition: function (e) {
    e.preventDefault();
    var href = $(e.currentTarget).attr('href'),
        transition = $(e.currentTarget).attr('data-transition'),
        direction = $(e.currentTarget).attr('data-direction');

    Backbone.trigger('page-transition', href, transition, direction );
  }
});

Поскольку ваш маршрутизатор уже зарегистрирован в событии page-transition из объекта Backbone, он вызовет функцию router.animate с соответствующими аргументами.

Заключение

Этот шаблон можно использовать везде в вашем приложении Backbone, эти события можно прослушать с помощью любого расширенного объекта Backbone, возможно, это Collection, Model, View, Router... Вы можете создать специальный медиатор с этим одним слоем:

var mediator = _.extend({}, Backbone.Events);

Этот шаблон очень мощный, поскольку он способствует полной развязке между модулями. Ваши модули не должны знать, кто выполняет функции, они просто должны знать, что это не их ответственность, и предупредить приложение об этом, вызвав событие.