Not
Varyasyonlarının kullanılmasını öneren yanıtların $window.history.back()
tümü, sorunun önemli bir bölümünü gözden kaçırmıştır: Geçmiş atlarken uygulamanın durumunu doğru durum konumuna nasıl geri yükleyebilirim (geri / ileri / yenileme). Bunu akılda tutarak; lütfen okumaya devam edin.
Evet, saf bir ui-router
durum makinesini çalıştırırken tarayıcının geri / ileri (geçmiş) olması ve yenilenmesi mümkündür, ancak biraz yapmak gerekir.
Birkaç bileşene ihtiyacınız var:
Benzersiz URL'ler . Tarayıcı, yalnızca URL'leri değiştirdiğinizde geri / ileri düğmelerini etkinleştirir, bu nedenle ziyaret edilen durum başına benzersiz bir URL oluşturmanız gerekir. Bu url'lerin herhangi bir durum bilgisi içermesine gerek yoktur.
Bir Oturum Hizmeti . Üretilen her url belirli bir durumla ilişkilendirilir, bu nedenle url-durum çiftlerinizi saklamanın bir yoluna ihtiyacınız vardır, böylece açısal uygulamanız geri / ileri veya yenileme tıklamalarıyla yeniden başlatıldıktan sonra durum bilgilerini alabilirsiniz.
Bir Eyalet Tarihi . Benzersiz bir url ile anahtarlanmış ui-yönlendirici durumlarının basit bir sözlüğü. HTML5'e güvenebiliyorsanız HTML5 Geçmiş API'sini kullanabilirsiniz , ancak benim gibi yapamıyorsanız, birkaç satır kodda kendiniz uygulayabilirsiniz (aşağıya bakın).
Bir Konum Hizmeti . Son olarak, hem kodunuz tarafından dahili olarak tetiklenen ui-yönlendirici durum değişikliklerini hem de genellikle kullanıcının tarayıcı düğmelerini tıklaması veya tarayıcı çubuğuna bir şeyler yazmasıyla tetiklenen normal tarayıcı url değişikliklerini yönetebilmeniz gerekir. Bunların hepsi biraz yanıltıcı olabilir çünkü neyin neyi tetiklediği konusunda kafa karıştırmak kolaydır.
İşte bu gereksinimlerin her biri için benim uygulamam. Her şeyi üç hizmete ayırdım:
Oturum Hizmeti
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
Bu, javascript sessionStorage
nesnesi için bir sarmalayıcıdır . Burada netlik için kestim. Bunun tam açıklaması için lütfen bakınız: Bir AngularJS Tek Sayfa Uygulaması ile sayfa yenilemeyi nasıl hallederim?
Devlet Tarih Servisi
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
Üretilen, benzersiz URL'ler anahtarlı tarihsel devletlerin depolama ve alma sonrasında görünüyor. Gerçekten de sözlük tarzı bir nesne için kullanışlı bir paketleyicidir.
Eyalet Konum Hizmeti
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
İki olayı ele alır:
locationChange . Bu, tarayıcının konumu değiştirildiğinde, genellikle geri / ileri / yenile düğmesine basıldığında veya uygulama ilk başladığında veya kullanıcı bir url yazdığında çağrılır. StateHistoryService
İçinde mevcut location.url için bir durum mevcutsa, ui-router'lar aracılığıyla durumu geri yüklemek için kullanılır $state.go
.
stateChange . Bu, durumu dahili olarak taşıdığınızda denir. Mevcut durumun adı ve parametreleri, StateHistoryService
oluşturulan bir url tarafından anahtarlanmış olarak saklanır . Oluşturulan bu url istediğiniz herhangi bir şey olabilir, durumu insan tarafından okunabilir bir şekilde tanımlayabilir veya tanımlamayabilir. Benim durumumda bir durum parametresi artı bir kılavuzdan türetilmiş rastgele oluşturulmuş bir rakam dizisi kullanıyorum (kılavuz oluşturucu parçacığı için ayağa bakın). Oluşturulan url, tarayıcı çubuğunda görüntülenir ve en önemlisi, kullanılarak tarayıcının dahili geçmiş yığınına eklenir @location.url url
. İleri / geri düğmelerini etkinleştiren tarayıcının geçmiş yığınına url'nin eklenmesi.
Bu teknikle ilgili en büyük sorun @location.url url
, stateChange
yöntemi $locationChangeSuccess
çağırmanın olayı tetiklemesi ve dolayısıyla locationChange
yöntemi çağırmasıdır . Aynı şekilde @state.go
from öğesini çağırmak olayı ve dolayısıyla yöntemi locationChange
tetikleyecektir . Bu çok kafa karıştırıcı hale gelir ve tarayıcı geçmişini sonu gelmez bozar.$stateChangeSuccess
stateChange
Çözüm çok basit. preventCall
Dizinin yığın ( pop
ve push
) olarak kullanıldığını görebilirsiniz . Yöntemlerden biri her çağrıldığında, diğer yöntemin yalnızca tek seferlik olarak adlandırılmasını engeller. Bu teknik, $ olaylarının doğru tetiklenmesini engellemez ve her şeyi düz tutar.
Şimdi tek yapmamız gereken, HistoryService
yöntemleri durum geçiş yaşam döngüsünde uygun zamanda çağırmak . Bu, AngularJS Apps .run
yönteminde şu şekilde yapılır :
Açısal uygulama çalıştırma
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Bir Kılavuz Oluşturun
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
Tüm bunlar yerine getirildiğinde, ileri / geri düğmeleri ve yenileme düğmesi beklendiği gibi çalışır.