作者热门文章
- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我已经使用 ui-router 实现了一个 angularjs 单页应用程序.
最初我使用一个不同的 url 来识别每个状态,但这会导致不友好的、GUID 打包的 url。
所以我现在将我的网站定义为一个更简单的状态机。状态不是由 url 标识的,而是根据需要简单地转换为,如下所示:
定义嵌套状态
angular
.module 'app', ['ui.router']
.config ($stateProvider) ->
$stateProvider
.state 'main',
templateUrl: 'main.html'
controller: 'mainCtrl'
params: ['locationId']
.state 'folder',
templateUrl: 'folder.html'
parent: 'main'
controller: 'folderCtrl'
resolve:
folder:(apiService) -> apiService.get '#base/folder/#locationId'
#The ui-sref attrib transitions to the 'folder' state
a(ui-sref="folder({locationId:'{{folder.Id}}'})")
| {{ folder.Name }}
最佳答案
注意
建议使用 $window.history.back()
的变体的答案都错过了问题的关键部分:如何在历史跳转(后退/前进/刷新)时将应用程序的状态恢复到正确的状态位置。考虑到这一点;请继续阅读。
是的,可以在运行纯 ui-router
的同时让浏览器后退/前进(历史记录)和刷新。状态机,但需要做一些事情。
您需要几个组件:
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
sessionStorage
的包装器对象。为了清楚起见,我在这里将其删减。有关这方面的完整解释,请参阅:
How do I handle page refreshing with an AngularJS Single Page Application
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
处理两个事件:
StateHistoryService
中存在当前 location.url 的状态然后用于通过ui-router的$state.go
恢复状态. StateHistoryService
中由生成的 url 键控。这个生成的 url 可以是你想要的任何东西,它可能会或可能不会以人类可读的方式识别状态。在我的情况下,我使用状态参数加上从 guid 派生的随机生成的数字序列(请参阅 guid 生成器片段的脚)。生成的 url 显示在浏览器栏中,至关重要的是,使用 @location.url url
添加到浏览器的内部历史堆栈中。 .它将 url 添加到浏览器的历史堆栈中,以启用前进/后退按钮。 @location.url url
在
stateChange
方法将触发
$locationChangeSuccess
事件等调用
locationChange
方法。同等拨打
@state.go
来自
locationChange
将触发
$stateChangeSuccess
事件等
stateChange
方法。这会变得非常困惑,并且会无休止地弄乱浏览器历史记录。
preventCall
用作堆栈的数组(
pop
和
push
)。每次调用其中一个方法时,它都会阻止另一个方法只被调用一次。这种技术不会干扰 $ 事件的正确触发并保持一切正常。
HistoryService
状态转换生命周期中适当时间的方法。这是在 AngularJS 应用程序中完成的
.run
方法,像这样:
angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->
$rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
stateLocationService.stateChange()
$rootScope.$on '$locationChangeSuccess', ->
stateLocationService.locationChange()
Math.guid = ->
s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
"#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
关于javascript - 如何让后退按钮与 AngularJS ui-router 状态机一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22247294/
我是一名优秀的程序员,十分优秀!