Использование фрагмента URL-адреса (#) для модальных представлений в одностраничном приложении pushState

Мы используем Backbone.Router только в режиме pushstate, поэтому все наши клиентские маршруты не содержат хэшей.
Однако мы столкнулись с трудностями при реализации модальных представлений в нашем приложении.

Задача заключается в следующем:

  • Мы хотим, чтобы кнопка «Назад» скрывала текущее модальное представление (поэтому нам нужен URL-адрес);
  • Мы хотим, чтобы Forward показывал его снова, не перерисовывая все приложение;
  • Мы хотим иметь возможность показывать модальные окна «поверх» любого существующего маршрута, а не только на одной странице;
  • Мы хотим иметь возможность создавать ссылки, которые сразу показывают определенное модальное окно (например, модальное окно входа в систему).

Другими словами, мы хотим, чтобы модальные представления были представлены в истории.

Нашей первой попыткой было использовать URL типа /login для модального входа и обрабатывать их специально в обработчике route. Когда мы находимся на /otherpage, открытие модального окна будет переходить к /login, а когда модальное закроется, снова перейти к /otherpage.

Однако у этого есть очень серьезная проблема: URL-адрес типа /login не «знает», поверх которого он должен быть нарисован, поэтому нам приходится перерисовывать все, нажимая «Назад» и «Вперед».

Это на самом деле имеет смысл: URL-адрес модального входа на главном экране должен отличаться от URL-адреса модального входа на другой странице.

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

/
/#login
/otherpage
/otherpage#login

Это делает обработчик маршрутизации простым:

  • Во-первых, нарисуйте фактические виды на основе сопоставленного маршрута, как мы делали раньше.
  • После этого, если присутствует хеш, отобразить модальное представление сверху.

Это также соответствует идее о том, что хэш является «фрагментом» видимого документа. (Да, приложения — это не документы, бла-бла-бла. Мы по-прежнему хотим, чтобы они были адресуемыми.)

Есть ли в этом подходе проблемы?
Есть ли лучший подход, удовлетворяющий нашим условиям?


person Dan Abramov    schedule 13.02.2014    source источник


Ответы (1)


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

var Login = Backbone.Model.extend({
    closeLogin: function () {
        this.set({ open: false }, { silent: true });
        this.trigger('loginClosed');
    }
});

var LoginView = Backbone.View.extend({
    el: '#loginModal',     
    initialize: function () {
        this.listenTo(this.model, 'loginClosed', this.closeLogin);
    },
    closeLogin: function () {
        // do whatever you would normally do to close the modal
    }
});

var Router = Backbone.Router.extend({
    routes: {
        '/login': 'defaultRouteLogin',
        '': 'defaultRoute',
        'otherpage/login': 'otherPageRouteLogin',
        'otherpage': 'otherPageRoute'
    },
    defaultRoute: function () {
        // defaultRoute behaviors
        this.login.closeLogin();
    },
    defaultRouteLogin: function () {
        // defaultRoute behavior
        // instantiate login modal
    },
    otherPageRoute: function () {
        // otherPageRoute behavior
        this.login.closeLogin();
    },
    otherPageRouteLogin: function () {
        // otherPageRoute behavior
        // instantiate login modal
    },
    initialize: function () {
        this.login = new Login();
        this.loginView = new LoginView({ model: this.login });
    }
});

Чтобы поддерживать поведение кнопки «Назад», используйте метод, который закрывает модальное окно входа на каждом маршруте, где вы можете открыть свое модальное окно. Обязательно правильно упорядочивайте маршруты.

person kinakuta    schedule 13.02.2014
comment
Это сработало бы, если бы у нас было несколько маршрутов. У нас их уже более 10, и количество будет расти. - person Dan Abramov; 14.02.2014
comment
Я использовал эту технику в SPA с более чем 30 маршрутами. Добавление дополнительных маршрутов для его поддержки было довольно тривиальным, потому что все они делали одно и то же - может быть способ сделать это более сухим, но мне это не было очевидно, когда я это делал. - person kinakuta; 14.02.2014
comment
На самом деле, это имеет смысл как наименее навязчивое решение. Более того, я могу генерировать эти маршруты в любом случае на основе набора маршрутов без входа в систему. - person Dan Abramov; 14.02.2014