注意
のバリエーションを使用することを提案する回答$window.history.back()
はすべて、質問の重要な部分を逃しています。履歴がジャンプするときに、アプリケーションの状態を正しい状態の場所に復元する方法(戻る/進む/更新)。それを念頭に置いて。読んでください。
はい、純粋なui-router
ステートマシンを実行している間にブラウザを元に戻したり(履歴)更新したりすることは可能ですが、少し時間がかかります。
いくつかのコンポーネントが必要です。
一意のURL。ブラウザは、URLを変更したときにのみ戻る/進むボタンを有効にするため、訪問した状態ごとに一意のURLを生成する必要があります。ただし、これらのURLには状態情報を含める必要はありません。
セッションサービス。生成された各URLは特定の状態に関連付けられるため、バック/フォワードまたはリフレッシュクリックによって角度付きアプリが再起動された後に状態情報を取得できるように、URLと状態のペアを保存する方法が必要です。
州の歴史。一意のURLをキーにしたui-router状態の単純な辞書。HTML5に依存できる場合は、HTML5 History APIを使用できますが、私のようにできない場合は、数行のコードで自分で実装できます(下記を参照)。
位置サービス。最後に、コードによって内部的にトリガーされるui-router状態の変更と、ユーザーがブラウザーボタンをクリックするかブラウザーバーに何かを入力することによって通常トリガーされる通常のブラウザーURL変更の両方を管理できる必要があります。何が何をトリガーしたかについて混乱するのは簡単なので、これはすべて少しトリッキーになります。
これらの要件のそれぞれの私の実装です。私はすべてを3つのサービスにバンドルしました:
セッションサービス
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
# other properties goes here
accessor:(name, value)->
return @getStorage name unless value?
@setStorage name, value
angular
.module 'app.Services'
.service 'sessionService', SessionService
これは、javascript 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}
#generate your site specific, unique url here
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
2つのイベントを処理します。
locationChange。これは、ブラウザの場所が変更されたとき、通常は戻る/進む/更新ボタンが押されたとき、アプリが最初に起動したとき、またはユーザーがURLを入力したときに呼び出されます。現在のlocation.urlの状態がに存在する場合は、StateHistoryService
ui-routerを介して状態を復元するために使用されます$state.go
。
stateChange。これは、内部で状態を移動するときに呼び出されます。現在の状態の名前とパラメータはStateHistoryService
、生成されたURLをキーとして格納されます。この生成されたURLは、あなたが望むものにすることができます。人間が読める方法で状態を識別してもしなくてもかまいません。私の場合、私は状態パラメーターに加えて、GUIDから派生したランダムに生成された一連の数字を使用しています(GUIDジェネレーターのスニペットについては、脚を参照してください)。生成されたURLはブラウザバーに表示され、重要なことに、を使用してブラウザの内部履歴スタックに追加されます@location.url url
。ブラウザーの履歴スタックにURLを追加して、進む/戻るボタンを有効にします。
この手法の大きな問題@location.url url
は、stateChange
メソッドを$locationChangeSuccess
呼び出すとイベントがトリガーされ、メソッドが呼び出されるlocationChange
ことです。同様に@state.go
from locationChange
を呼び出すと、$stateChangeSuccess
イベントがトリガーされ、stateChange
メソッドがトリガーされます。これは非常に混乱し、終わりのないブラウザの履歴を台無しにしてしまいます。
解決策は非常に簡単です。preventCall
配列がスタックとして使用されていることがわかります(pop
およびpush
)。メソッドの1つが呼び出されるたびに、他のメソッドが1回だけ呼び出されるのを防ぎます。この手法は、$イベントの正しいトリガーを妨げず、すべてをまっすぐに保ちます。
あとHistoryService
は、状態遷移のライフサイクルの適切なタイミングでメソッドを呼び出すだけです。これは、AngularJS Apps .run
メソッドで次のように行われます。
Angular 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()}"
これがすべて整ったら、進む/戻るボタンと更新ボタンはすべて期待どおりに機能します。