Catatan
Jawaban yang menyarankan penggunaan variasi $window.history.back()
semuanya telah melewatkan bagian penting dari pertanyaan: Bagaimana cara mengembalikan status aplikasi ke lokasi-negara yang benar saat sejarah melompat (mundur / maju / refresh). Dengan pemikiran itu; tolong, baca terus.
Ya, adalah mungkin untuk membuat browser mundur / maju (riwayat) dan menyegarkan saat menjalankan mesin ui-router
negara murni tetapi itu membutuhkan sedikit kerja.
Anda membutuhkan beberapa komponen:
URL unik . Browser hanya mengaktifkan tombol mundur / maju saat Anda mengubah url, jadi Anda harus membuat url unik untuk setiap status yang dikunjungi. Url ini tidak perlu berisi informasi negara bagian apa pun.
Sebuah Layanan Sesi . Setiap url yang dihasilkan berkorelasi dengan kondisi tertentu sehingga Anda memerlukan cara untuk menyimpan pasangan status-url Anda sehingga Anda dapat mengambil informasi status setelah aplikasi sudut Anda dimulai ulang dengan klik mundur / maju atau segarkan.
Sejarah Negara . Kamus sederhana dari status ui-router yang dikunci oleh url unik. Jika Anda dapat mengandalkan HTML5 maka Anda dapat menggunakan API Riwayat HTML5 , tetapi jika, seperti saya, Anda tidak dapat menerapkannya sendiri dalam beberapa baris kode (lihat di bawah).
Sebuah Layanan Lokasi . Terakhir, Anda harus dapat mengelola kedua perubahan status ui-router, yang dipicu secara internal oleh kode Anda, dan perubahan url browser normal biasanya dipicu oleh pengguna yang mengklik tombol browser atau mengetik sesuatu ke dalam bilah browser. Ini semua bisa menjadi sedikit rumit karena mudah untuk menjadi bingung tentang apa yang memicu apa.
Berikut adalah implementasi saya untuk masing-masing persyaratan tersebut. Saya telah menggabungkan semuanya menjadi tiga layanan:
Layanan Sesi
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
Ini adalah pembungkus untuk sessionStorage
objek javascript . Saya telah memotongnya untuk kejelasan di sini. Untuk penjelasan lengkap tentang ini, silakan lihat: Bagaimana cara menangani penyegaran halaman dengan Aplikasi Halaman Tunggal AngularJS
Layanan Sejarah Negara
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
The StateHistoryService
terlihat setelah penyimpanan dan pengambilan negara sejarah mengetik dengan yang dihasilkan, url yang unik. Ini benar-benar hanya pembungkus kenyamanan untuk objek gaya kamus.
Layanan Lokasi Negara
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
The StateLocationService
menangani dua peristiwa:
locationChange . Ini dipanggil saat lokasi browser diubah, biasanya saat tombol kembali / maju / segarkan ditekan atau saat aplikasi pertama kali dimulai atau saat pengguna mengetikkan url. Jika status untuk location.url saat ini ada, StateHistoryService
maka status itu digunakan untuk memulihkan status melalui ui-router $state.go
.
stateChange . Ini dipanggil saat Anda memindahkan status secara internal. Nama negara bagian saat ini dan params disimpan dalam StateHistoryService
kunci oleh url yang dihasilkan. Url yang dihasilkan ini dapat berupa apa pun yang Anda inginkan, mungkin atau mungkin tidak mengidentifikasi negara dengan cara yang dapat dibaca manusia. Dalam kasus saya, saya menggunakan param negara ditambah urutan digit yang dihasilkan secara acak yang berasal dari pedoman (lihat kaki untuk cuplikan generator pedoman). Url yang dihasilkan ditampilkan di bilah browser dan, yang terpenting, ditambahkan ke tumpukan riwayat internal browser menggunakan @location.url url
. Ini menambahkan url ke tumpukan riwayat browser yang memungkinkan tombol maju / mundur.
Masalah besar dengan teknik ini adalah bahwa menelepon @location.url url
dalam stateChange
metode akan memicu $locationChangeSuccess
acara dan memanggil locationChange
metode. Dengan cara yang sama memanggil @state.go
from locationChange
akan memicu $stateChangeSuccess
kejadian dan begitu pula stateChange
metode. Ini menjadi sangat membingungkan dan mengacaukan riwayat browser tanpa akhir.
Solusinya sangat sederhana. Anda dapat melihat preventCall
array yang digunakan sebagai tumpukan ( pop
dan push
). Setiap kali salah satu metode dipanggil, ia mencegah metode lain disebut hanya satu kali. Teknik ini tidak mengganggu pemicu peristiwa $ yang benar dan menjaga semuanya tetap lurus.
Sekarang yang perlu kita lakukan adalah memanggil HistoryService
metode pada waktu yang tepat dalam siklus hidup transisi status. Ini dilakukan dalam .run
metode Aplikasi AngularJS , seperti ini:
App.run sudut
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Hasilkan Panduan
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
Dengan semua ini di tempatnya, tombol maju / mundur dan tombol segarkan semuanya berfungsi seperti yang diharapkan.