Uwaga
Odpowiedzi, które sugerują użycie wariacji $window.history.back()
, pominęły kluczową część pytania: Jak przywrócić stan aplikacji do prawidłowej lokalizacji stanu, gdy historia przeskakuje (wstecz / dalej / odświeżanie). Pamiętając o tym; proszę, czytaj dalej.
Tak, możliwe jest, aby przeglądarka przeszła wstecz / do przodu (historia) i odświeżyła się podczas uruchamiania czystego ui-router
automatu stanowego, ale zajmuje to trochę czasu.
Potrzebujesz kilku komponentów:
Unikalne adresy URL . Przeglądarka włącza przyciski Wstecz / Dalej tylko podczas zmiany adresów URL, więc musisz wygenerować unikalny adres URL dla każdego odwiedzonego stanu. Te adresy URL nie muszą jednak zawierać żadnych informacji o stanie.
Usługa sesji . Każdy wygenerowany adres URL jest skorelowany z określonym stanem, więc potrzebujesz sposobu na przechowywanie par stanu adresu URL, aby można było pobrać informacje o stanie po ponownym uruchomieniu aplikacji kątowej za pomocą kliknięć wstecz / do przodu lub odświeżania.
Historia stanu . Prosty słownik stanów routera ui z kluczem unikalnym adresem URL. Jeśli możesz polegać na HTML5, możesz użyć interfejsu API historii HTML5 , ale jeśli tak jak ja nie możesz, możesz zaimplementować go samodzielnie w kilku wierszach kodu (patrz poniżej).
Usługa lokalizacji . Wreszcie, musisz mieć możliwość zarządzania zarówno zmianami stanu routera ui, wywoływanymi wewnętrznie przez Twój kod, jak i normalnymi zmianami adresu URL przeglądarki, zwykle wywoływanymi przez użytkownika klikającego przyciski przeglądarki lub wpisującego coś na pasku przeglądarki. To wszystko może być nieco skomplikowane, ponieważ łatwo jest zdezorientować, co spowodowało co.
Oto moja implementacja każdego z tych wymagań. Powiązałem wszystko w trzy usługi:
Usługa sesji
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
To jest opakowanie dla sessionStorage
obiektu javascript . Obciąłem to dla jasności. Aby uzyskać pełne wyjaśnienie, zobacz: Jak obsłużyć odświeżanie strony za pomocą aplikacji jednostronicowej AngularJS
Usługa historii stanu
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
Do StateHistoryService
dba przechowywania i udostępniania stanów historycznych kluczach będących generowanych, unikalnych adresów URL. Tak naprawdę jest to po prostu wygodna aplikacja dla obiektu w stylu słownika.
Stanowa usługa lokalizacji
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
Obsługuje dwa zdarzenia:
locationChange . Jest to wywoływane w przypadku zmiany lokalizacji przeglądarki, zwykle po naciśnięciu przycisku Wstecz / Dalej / Odśwież lub po pierwszym uruchomieniu aplikacji lub gdy użytkownik wpisze adres URL. Jeśli stan dla bieżącej lokalizacji.url istnieje w, StateHistoryService
to jest używany do przywrócenia stanu za pośrednictwem routera ui $state.go
.
stateChange . Nazywa się to, gdy przenosisz stan wewnętrznie. Nazwa i parametry bieżącego stanu są przechowywane w StateHistoryService
kluczu przez wygenerowany adres URL. Ten wygenerowany adres URL może być dowolny, może, ale nie musi, identyfikować stan w sposób czytelny dla człowieka. W moim przypadku używam parametru stanu oraz losowo generowanej sekwencji cyfr pochodzących z guid (patrz stopa dla fragmentu generatora guid). Wygenerowany adres URL jest wyświetlany na pasku przeglądarki i, co najważniejsze, dodawany do wewnętrznego stosu historii przeglądarki za pomocą @location.url url
. Dodaje adres URL do stosu historii przeglądarki, który włącza przyciski Dalej / Wstecz.
Duży problem z tej techniki jest to, że wywołanie @location.url url
w stateChange
metodzie wywoła $locationChangeSuccess
zdarzenie i tak wywołać locationChange
metodę. Równie wywołanie @state.go
from locationChange
wyzwoli $stateChangeSuccess
zdarzenie, a więcstateChange
metodę. To staje się bardzo mylące i bez końca psuje historię przeglądarki.
Rozwiązanie jest bardzo proste. Możesz zobaczyć preventCall
tablicę używaną jako stos ( pop
ipush
). Za każdym razem, gdy wywoływana jest jedna z metod, zapobiega to jednorazowemu wywołaniu drugiej metody. Ta technika nie koliduje z prawidłowym wyzwalaniem zdarzeń $ i utrzymuje wszystko prosto.
Teraz wszystko, co musimy zrobić, to wywołać HistoryService
metody w odpowiednim momencie cyklu życia zmiany stanu. Odbywa się to w .run
metodzie AngularJS Apps , na przykład:
Angular app.run
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Wygeneruj Guid
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
Po tym wszystkim przyciski do przodu / do tyłu i przycisk odświeżania działają zgodnie z oczekiwaniami.