如何在ui-router中持久化浏览器上的可选状态参数

How to persist optional state parameter on browser back in ui-router?

本文关键字:状态 参数 浏览器 ui-router 持久化      更新时间:2023-09-26

我有一个父状态里面有两个子状态我将显示一个基于URL的状态

在这两个states中,一个有param1param2这样的参数,我在状态定义中使用了ui-router的params选项。

国家

$stateProvider.state('tabs.account', {
    url: '/account',
    views: {
        'content@tabs': {
            templateUrl: 'account.html',
            controller: function($scope, $stateParams) {
                //This params are internally used to make ajax and show some data.
                $scope.param1 = $stateParams.param1;
                $scope.param2 = $stateParams.param2;
            },
        }
    },
    params: {
        param1: { value: null }, //this are optional param
        param2: { value: null } //because they are not used in url
    }
});

如果你看看我的路由,params选项并没有真正在URL中引入,这就是为什么我认为它是可选的。

看看plunkr,我已经展示了两个选项卡Account & ,

  1. 点击调查选项卡,然后在textarea中添加一些显示的数据。
  2. 点击转到帐户,将这些textarea值传递给通过在锚

  3. 上执行ui-sref="tabs.account({param1: thing1, param2: thing2})"来更改另一个帐户选项卡
  4. 现在你将看到param1 &从$stateParams

  5. 中分配给范围的html的param2值现在再次点击调查标签,您将进入调查页面。
  6. 点击浏览器返回,你会注意到param的值没有得到null

问题Plunkr

我相信你得到了我想问的,为什么可选参数值没有被存储?因为他们已经是国家的一部分。

我知道我可以用以下两种方法来解决这个问题。

  • 通过创建一个服务来在两个视图之间共享数据。
  • 通过在状态URL中添加参数。像url: '/account/:param1/:param2',(但我不喜欢这个)

我已经尝试过angular-ui-路由器 sticky states ,但这似乎不适合我。有什么更好的方法吗?

有什么方法可以让我的用例工作,任何想法都将不胜感激。

Github Issue Link Here

我会将params定义移动到父状态,以便在您的两个子状态之间共享可选状态参数。

子状态将从父状态继承$stateParams,因此不需要真正的"变通方法"。

只要像往常一样在子控制器中注入$stateParams,您就可以完全访问正在传递的参数。如果不想在特定的子状态中使用参数,只需避免注入它们。

这适用于;

  • 后退按钮
  • 前进按钮
  • ui-sref (不带参数(保持原样))
  • ui-sref (带参数(将覆盖))

$stateProvider
  .state('parent', {
    params: { p1: null, p2: null }
  })
  .state('parent.childOne', {
    url: '/one',
    controller: function ($stateParams) {
      console.log($stateParams); // { p1: null, p2: null }
    }
  })
  .state('parent.childTwo', {
    url: '/two',
    controller: function ($stateParams) {
      console.log($stateParams); // { p1: null, p2: null }
    }
  })

如果您在parent的状态树中旅行时想要清除参数,则必须手动执行

这将是唯一的真正的警告,我可以看到通过使用这个解决方案。

我知道在你提出的情况下,手动清理可能不可取,但你并没有积极反对,因此我觉得这个建议是有价值的。

更新的plunker

一个解决方案是缓存状态参数,并在进入tabs.account状态时有条件地加载它们。UI Router状态配置实际上允许你为这些类型的"进入状态时做点什么"的情况提供一个onEnter回调。

下面是使用localStorage作为缓存的基本逻辑,这里有工作的Plunker:

  • 当您进入tabs.account状态时,检查您的状态参数
    • 如果你有,缓存到本地存储
    • 如果没有,从本地存储加载到$stateParams

这里有一个示例代码片段供参考(取自Plunker):

  $stateProvider.state('tabs.account', {
    ...
    onEnter: ['$stateParams', '$window', function($stateParams, $window) {
      if($stateParams.param1) {
        $window.localStorage.setItem('tabs.account.param1', $stateParams.param1);
      } else {
        $stateParams.param1 = $window.localStorage.getItem('tabs.account.param1');
      }
      if($stateParams.param2) {
        $window.localStorage.setItem('tabs.account.param2', $stateParams.param2);
      } else {
        $stateParams.param2 = $window.localStorage.getItem('tabs.account.param2');
      }
    }],
    ...
  }

一个警告是你的参数将无限期地持续(例如跨刷新和会话)。为了解决这个问题,您可以在应用程序加载时清除缓存,如app.run所示。

最后需要注意的是,在Plunker中,我直接访问了本地存储(通过Angular的$window服务)。你可能想使用一些AngularJS模块——我已经在生产中使用了angular-local-storage。

我相信,如果不使用您提供的两种解决方案之一,您想要实现的目标是不可能实现的。

浏览器后退按钮只是保存URL历史记录。他不知道ui-router的内部状态,只会强迫URL改变。

强制修改URL会触发ui-router内部机器,但不幸的是,ui-router会看到URL的变化,就像有人手工修改URL一样。

Ui-router将触发一个新的路由变更到URL所指向的路由。这意味着他不知道你想"回去",只会在没有任何参数的情况下将状态更改为新状态。

单击后退按钮将根据URL触发状态更改为新的状态,而不是返回到以前的状态。

这就是为什么在URL中添加参数可以解决这个问题。因为URL是歧视性的,你最终会到达你想要的状态。

希望有帮助。

对我来说这听起来像是xy问题。有一些建议的方法可以使状态参数持久化,而问题位于这个表面之外。

根据问题的定义,数据应该独立于状态。所以这是一种与国家相关的全球性问题。因此,应该有一个服务来维护它,并且两种状态的控制器都需要维护它。只是不要在状态参数中传递超出某个状态作用域的数据。

Sticky状态很容易适应这种方法,因为它允许在另一个状态处于活动状态时保持DOM和$scope。但是当状态被重新激活时,它与状态参数无关。