gpt4 book ai didi

javascript - 如何让后退按钮与 AngularJS ui-router 状态机一起使用?

转载 作者:IT王子 更新时间:2023-10-29 02:45:53 26 4
gpt4 key购买 nike

我已经使用 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 }}

这个系统运行良好,我喜欢它简洁的语法。但是,由于我没有使用 url,后退按钮不起作用。

如何保持我整洁的 ui-router 状态机但启用后退按钮功能?

最佳答案

注意

建议使用 $window.history.back() 的变体的答案都错过了问题的关键部分:如何在历史跳转(后退/前进/刷新)时将应用程序的状态恢复到正确的状态位置。考虑到这一点;请继续阅读。

是的,可以在运行纯 ui-router 的同时让浏览器后退/前进(历史记录)和刷新。状态机,但需要做一些事情。

您需要几个组件:

  • 唯一网址。浏览器仅在您更改 url 时启用后退/前进按钮,因此您必须为每个访问状态生成一个唯一的 url。不过,这些 url 不需要包含任何状态信息。
  • session 服务。每个生成的 url 都与特定状态相关,因此您需要一种方法来存储 url-state 对,以便您可以在通过后退/前进或刷新点击重新启动 angular 应用程序后检索状态信息。
  • 国家历史。一个由唯一 url 键控的 ui-router 状态的简单字典。如果您可以依赖 HTML5,那么您可以使用 HTML5 History API ,但如果像我一样,你不能,那么你可以用几行代码自己实现它(见下文)。
  • 定位服务。最后,您需要能够管理由代码内部触发的 ui-router 状态更改,以及通常由用户单击浏览器按钮或在浏览器栏中输入内容触发的正常浏览器 url 更改。这一切都会变得有点棘手,因为很容易混淆触发了什么。

  • 这是我对这些要求中的每一个的实现。我已将所有内容捆绑为三项服务:

    session 服务
    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 的包装器对象。为了清楚起见,我在这里将其删减。有关这方面的完整解释,请参阅: 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处理两个事件:
  • 位置改变。这在浏览器位置更改时调用,通常是在按下后退/前进/刷新按钮时或应用程序首次启动时或用户输入 url 时。如果 StateHistoryService 中存在当前 location.url 的状态然后用于通过ui-router的$state.go恢复状态.
  • 状态变化。当您在内部移动状态时会调用它。当前状态的名称和参数存储在 StateHistoryService 中由生成的 url 键控。这个生成的 url 可以是你想要的任何东西,它可能会或可能不会以人类可读的方式识别状态。在我的情况下,我使用状态参数加上从 guid 派生的随机生成的数字序列(请参阅 guid 生成器片段的脚)。生成的 url 显示在浏览器栏中,至关重要的是,使用 @location.url url 添加到浏览器的内部历史堆栈中。 .它将 url 添加到浏览器的历史堆栈中,以启用前进/后退按钮。

  • 这种技术的大问题是调用 @location.url urlstateChange方法将触发 $locationChangeSuccess事件等调用 locationChange方法。同等拨打 @state.go来自 locationChange将触发 $stateChangeSuccess事件等 stateChange方法。这会变得非常困惑,并且会无休止地弄乱浏览器历史记录。

    解决方法很简单。您可以看到 preventCall用作堆栈的数组( poppush )。每次调用其中一个方法时,它都会阻止另一个方法只被调用一次。这种技术不会干扰 $ 事件的正确触发并保持一切正常。

    现在我们需要做的就是拨打 HistoryService状态转换生命周期中适当时间的方法。这是在 AngularJS 应用程序中完成的 .run方法,像这样:

    Angular 应用程序运行
    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/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com