노트
의 변형 사용을 제안하는 답변 $window.history.back()
은 모두 다음 질문의 중요한 부분을 놓쳤습니다 . 기록이 점프 할 때 응용 프로그램의 상태 를 올바른 상태 위치로 복원하는 방법 (뒤로 / 앞으로 / 새로 고침). 이를 염두에두고; 계속 읽어주세요.
예, 순수 ui-router
상태 머신 을 실행하는 동안 브라우저를 뒤로 / 앞으로 (기록) 새로 고칠 수 있지만 약간의 작업이 필요합니다.
몇 가지 구성 요소가 필요합니다.
고유 URL . 브라우저는 URL을 변경할 때만 뒤로 / 앞으로 버튼을 활성화하므로 방문한 상태별로 고유 한 URL을 생성해야합니다. 이 URL은 상태 정보를 포함 할 필요가 없습니다.
세션 서비스 . 생성 된 각 URL은 특정 상태와 상관 관계가 있으므로 url-state 쌍을 저장하는 방법이 필요하므로 각도 앱이 뒤로 / 앞으로 또는 새로 고침 클릭으로 다시 시작된 후 상태 정보를 검색 할 수 있습니다.
국가 역사 . 고유 URL로 키가 지정된 ui-router 상태의 간단한 사전입니다. HTML5에 의존 할 수 있다면 HTML5 History API를 사용할 수 있지만 저처럼 할 수없는 경우 몇 줄의 코드로 직접 구현할 수 있습니다 (아래 참조).
위치 서비스 . 마지막으로, 코드에 의해 내부적으로 트리거되는 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
개체 의 래퍼입니다 . 여기서 명확성을 위해 줄였습니다. 이에 대한 자세한 설명은 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
생성 고유 URL에 의해 키잉 과거 상태의 저장 및 회수 후에 보인다. 실제로 사전 스타일 객체에 대한 편의 래퍼입니다.
주 위치 서비스
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의 .url을 통해 상태를 복원하는 데 사용됩니다 $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
상태 전환 수명주기에서 적절한 시간에 메서드를 호출하는 것 입니다. 이것은 AngularJS Apps .run
메서드에서 다음과 같이 수행됩니다 .
각도 app.run
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Guid 생성
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
이 모든 것이 제자리에 있으면 앞으로 / 뒤로 버튼과 새로 고침 버튼이 모두 예상대로 작동합니다.