Заметка
Все ответы, предлагающие использовать варианты $window.history.back()
, упускают из виду важную часть вопроса: как восстановить состояние приложения до правильного местоположения состояния при переходе истории (назад / вперед / обновить). С этим в мыслях; пожалуйста, читайте дальше.
Да, можно переключать браузер назад / вперед (история) и обновлять во время работы чистого ui-router
конечного автомата, но это требует некоторых усилий.
Вам понадобится несколько компонентов:
Уникальные URL-адреса . Браузер включает кнопки «назад / вперед» только при изменении URL-адресов, поэтому вы должны создать уникальный URL-адрес для каждого посещенного состояния. Однако эти URL-адреса не должны содержать никакой информации о состоянии.
Сессионная служба . Каждый сгенерированный URL-адрес соотносится с определенным состоянием, поэтому вам нужен способ хранения ваших пар URL-состояние, чтобы вы могли получать информацию о состоянии после перезапуска приложения angular с помощью щелчков назад / вперед или обновления.
Государственная история . Простой словарь состояний ui-router с ключом по уникальному URL-адресу. Если вы можете положиться на HTML5, вы можете использовать API истории HTML5 , но если вы, как я, не можете, вы можете реализовать его самостоятельно в нескольких строках кода (см. Ниже).
Служба определения местоположения . Наконец, вам необходимо иметь возможность управлять как изменениями состояния ui-router, инициируемыми внутри вашего кода, так и обычными изменениями URL-адресов браузера, которые обычно запускаются пользователем, нажимая кнопки браузера или вводя данные в строку браузера. Все это может быть немного сложно, потому что легко запутаться в том, что что вызвало.
Вот моя реализация каждого из этих требований. Я объединил все в три службы:
Сессионная служба
class SessionService
setStorage:(key, value) ->
json = if value is undefined then null else JSON.stringify value
sessionStorage.setItem key, json
getStorage:(key)->
JSON.parse sessionStorage.getItem key
clear: ->
@setStorage(key, null) for key of sessionStorage
stateHistory:(value=null) ->
@accessor 'stateHistory', value
accessor:(name, value)->
return @getStorage name unless value?
@setStorage name, value
angular
.module 'app.Services'
.service 'sessionService', SessionService
Это оболочка для sessionStorage
объекта javascript . Я сократил это здесь для ясности. Полное объяснение этого вопроса см. В разделе: Как обрабатывать обновление страницы с помощью одностраничного приложения AngularJS
Государственная историческая служба
class StateHistoryService
@$inject:['sessionService']
constructor:(@sessionService) ->
set:(key, state)->
history = @sessionService.stateHistory() ? {}
history[key] = state
@sessionService.stateHistory history
get:(key)->
@sessionService.stateHistory()?[key]
angular
.module 'app.Services'
.service 'stateHistoryService', StateHistoryService
На StateHistoryService
внешнем виде после хранения и извлечения исторических состояний введенных пользователя с помощью сгенерированных уникальных адресов. На самом деле это просто удобная оболочка для объекта словарного стиля.
Государственная служба геолокации
class StateLocationService
preventCall:[]
@$inject:['$location','$state', 'stateHistoryService']
constructor:(@location, @state, @stateHistoryService) ->
locationChange: ->
return if @preventCall.pop('locationChange')?
entry = @stateHistoryService.get @location.url()
return unless entry?
@preventCall.push 'stateChange'
@state.go entry.name, entry.params, {location:false}
stateChange: ->
return if @preventCall.pop('stateChange')?
entry = {name: @state.current.name, params: @state.params}
url = "/#{@state.params.subscriptionUrl}/#{Math.guid().substr(0,8)}"
@stateHistoryService.set url, entry
@preventCall.push 'locationChange'
@location.url url
angular
.module 'app.Services'
.service 'stateLocationService', StateLocationService
StateLocationService
Обрабатывает два события:
locationChange . Это вызывается при изменении местоположения браузеров, обычно при нажатии кнопки назад / вперед / обновления, при первом запуске приложения или при вводе пользователем URL-адреса. Если состояние для текущего location.url существует в, StateHistoryService
то оно используется для восстановления состояния через ui-router $state.go
.
stateChange . Это вызывается, когда вы перемещаете состояние внутри. Имя и параметры текущего состояния хранятся в StateHistoryService
сгенерированном URL-адресе с ключом. Этот сгенерированный URL-адрес может быть любым, он может идентифицировать или не определять состояние в удобочитаемой форме. В моем случае я использую параметр состояния плюс случайно сгенерированную последовательность цифр, полученных из guid (фрагмент генератора guid см. В Foot). Сгенерированный URL-адрес отображается в строке браузера и, что особенно важно, добавляется во внутренний стек истории браузера с помощью @location.url url
. Он добавляет URL-адрес в стек истории браузера, который включает кнопки вперед / назад.
Большая проблема с этой техникой, что вызов @location.url url
в stateChange
методе вызовет $locationChangeSuccess
событие и так вызовите locationChange
метод. В равной степени вызов @state.go
from locationChange
вызовет $stateChangeSuccess
событие, а значит, и stateChange
метод. Это очень сбивает с толку и бесконечно портит историю браузера.
Решение очень простое. Вы можете видеть, что preventCall
массив используется как стек ( pop
и push
). Каждый раз, когда вызывается один из методов, он предотвращает одноразовый вызов другого метода. Этот метод не мешает правильному запуску событий $ и сохраняет все в порядке.
Теперь все, что нам нужно сделать, это вызвать HistoryService
методы в подходящее время в жизненном цикле перехода между состояниями. Это делается в .run
методе AngularJS Apps , например:
Angular app.run
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Создать гид
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
После всего этого кнопки вперед / назад и кнопка обновления работают должным образом.