Ghi chú
Các câu trả lời đề xuất sử dụng các biến thể của $window.history.back()
đều đã bỏ lỡ một phần quan trọng của câu hỏi: Làm thế nào để khôi phục trạng thái của ứng dụng về vị trí trạng thái chính xác khi lịch sử nhảy (lùi / chuyển tiếp / làm mới). Với ý nghĩ đó; làm ơn, hãy đọc tiếp.
Có, có thể để trình duyệt quay lại / chuyển tiếp (lịch sử) và làm mới trong khi chạy một ui-router
máy trạng thái thuần túy nhưng phải thực hiện một chút.
Bạn cần một số thành phần:
URL duy nhất . Trình duyệt chỉ bật nút quay lại / chuyển tiếp khi bạn thay đổi url, vì vậy bạn phải tạo một url duy nhất cho mỗi trạng thái đã truy cập. Mặc dù vậy, các url này không cần chứa bất kỳ thông tin trạng thái nào.
Một dịch vụ phiên . Mỗi url được tạo có tương quan với một trạng thái cụ thể, vì vậy bạn cần có cách lưu trữ các cặp trạng thái url của mình để bạn có thể truy xuất thông tin trạng thái sau khi ứng dụng góc của bạn được khởi động lại bằng các nhấp chuột lùi / chuyển tiếp hoặc làm mới.
A State History . Một từ điển đơn giản về các trạng thái ui-router được khóa bằng url duy nhất. Nếu bạn có thể dựa vào HTML5 thì bạn có thể sử dụng API lịch sử HTML5 , nhưng nếu, giống như tôi, bạn không thể thì bạn có thể tự triển khai nó trong một vài dòng mã (xem bên dưới).
Một Dịch vụ Vị trí . Cuối cùng, bạn cần có thể quản lý cả các thay đổi trạng thái ui-router, được kích hoạt nội bộ bởi mã của bạn và các thay đổi url trình duyệt thông thường thường được kích hoạt bởi người dùng nhấp vào các nút trình duyệt hoặc nhập nội dung vào thanh trình duyệt. Tất cả điều này có thể trở nên phức tạp một chút vì rất dễ bị nhầm lẫn về điều gì đã kích hoạt điều gì.
Đây là cách thực hiện của tôi đối với từng yêu cầu này. Tôi đã gói mọi thứ thành ba dịch vụ:
Dịch vụ phiên
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
Đây là một trình bao bọc cho sessionStorage
đối tượng javascript . Tôi đã cắt nó xuống cho rõ ràng ở đây. Để có giải thích đầy đủ về điều này, vui lòng xem: Làm cách nào để xử lý việc làm mới trang bằng Ứng dụng Trang đơn AngularJS
Dịch vụ Lịch sử Tiểu bang
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
Việc StateHistoryService
trông coi việc lưu trữ và truy xuất các trạng thái lịch sử được khóa bằng các url duy nhất, được tạo. Nó thực sự chỉ là một trình bao bọc tiện lợi cho một đối tượng kiểu từ điển.
Dịch vụ Vị trí Tiểu bang
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
Các StateLocationService
xử lý hai sự kiện:
locationChange . Điều này được gọi khi vị trí của trình duyệt bị thay đổi, thường là khi nhấn nút quay lại / chuyển tiếp / làm mới hoặc khi ứng dụng khởi động lần đầu tiên hoặc khi người dùng nhập url. Nếu trạng thái cho location.url hiện tại tồn tại trong StateHistoryService
thì nó được sử dụng để khôi phục trạng thái thông qua ui-router's $state.go
.
stateChange . Điều này được gọi khi bạn di chuyển trạng thái trong nội bộ. Tên và thông số của trạng thái hiện tại được lưu trữ trong StateHistoryService
khóa được tạo bởi một url được tạo. Url được tạo này có thể là bất kỳ thứ gì bạn muốn, nó có thể hoặc không thể xác định trạng thái theo cách con người có thể đọc được. Trong trường hợp của tôi, tôi đang sử dụng một tham số trạng thái cộng với một chuỗi chữ số được tạo ngẫu nhiên bắt nguồn từ một hướng dẫn (xem chân để biết đoạn mã trình tạo hướng dẫn). Url đã tạo được hiển thị trong thanh trình duyệt và quan trọng là được thêm vào ngăn xếp lịch sử nội bộ của trình duyệt bằng cách sử dụng @location.url url
. Nó thêm url vào ngăn xếp lịch sử của trình duyệt cho phép các nút chuyển tiếp / quay lại.
Vấn đề lớn với kỹ thuật này là việc gọi @location.url url
trong stateChange
phương thức sẽ kích hoạt $locationChangeSuccess
sự kiện và do đó hãy gọi locationChange
phương thức. Việc gọi @state.go
từ bằng nhau locationChange
sẽ kích hoạt $stateChangeSuccess
sự kiện và vì vậy stateChange
phương thức. Điều này rất khó hiểu và làm rối tung lịch sử trình duyệt.
Giải pháp này rất đơn giản. Bạn có thể thấy preventCall
mảng đang được sử dụng như một ngăn xếp ( pop
và push
). Mỗi khi một trong các phương thức được gọi, nó sẽ ngăn phương thức kia được gọi là một lần duy nhất. Kỹ thuật này không can thiệp vào việc kích hoạt chính xác các sự kiện $ và giữ cho mọi thứ luôn ổn định.
Bây giờ tất cả những gì chúng ta cần làm là gọi các HistoryService
phương thức vào thời điểm thích hợp trong vòng đời chuyển đổi trạng thái. Điều này được thực hiện trong .run
phương pháp AngularJS Apps , như sau:
Angular app.run
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Tạo hướng dẫn
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
Với tất cả những điều này, các nút tiến / lùi và nút làm mới đều hoạt động như mong đợi.