使用 Angular ui-router 设置 URL 查询参数而不改变状态

Posted

技术标签:

【中文标题】使用 Angular ui-router 设置 URL 查询参数而不改变状态【英文标题】:Set URL query parameters without state change using Angular ui-router 【发布时间】:2014-01-19 23:53:38 【问题描述】:

我应该如何使用 AngularJS 的 ui-router 使用不断变化的查询参数更新地址栏 URL 以在刷新页面时保持状态?

目前,每当输入更改时,我都会使用$state.transitionTo('search', q: 'updated search term'),但问题是这会重新加载控制器,重新绘制窗口并失去任何文本输入焦点。

有没有办法更新 stateParams 并将其同步到窗口 URL?

【问题讨论】:

我注意到 $state.go() 不会重新加载控制器,如果您将控制器定向到与您所处的状态相同的状态,只需更改参数即可。这对你有帮助吗? go 将重新加载控制器:angular-ui.github.io/ui-router/site/#/api/… 【参考方案1】:

编辑:今天又玩了一些,并意识到 angular ui-router 具有与本机 routerProvider 类似的选项:“reloadOnSearch”。

https://github.com/angular-ui/ui-router/wiki/Quick-Reference#options-1

默认设置为true,但如果你在你的状态下设置为false,那么当查询参数改变时状态改变不会发生。然后你可以调用$location.search(params);$location.search('param', value); 并且URL 会改变,但是ui-router 不会重新构建整个控制器/视图。您可能还需要在根范围内侦听 $locationChangeStart 事件以处理应用中的后退和前进历史操作,因为这些操作也不会导致状态更改。

我还在控制器范围内监听$stateChangeSuccess 事件,以捕获页面/路由的初始负载。

在 github 上有一些关于在路径更改(不仅仅是 URL 更改)中使用此功能的讨论:https://github.com/angular-ui/ui-router/issues/125 但我根本没有测试过,因为我的用例特定于查询字符串参数。

我的回答之前的版本提到了这个github问题:

https://github.com/angular-ui/ui-router/issues/562

但这是一个稍微不同的问题,特别是显示一种状态的模态而不是另一种状态的模态,而不改变非模态状态。我在那个问题中尝试了补丁,但很明显,它并不是为了防止整个状态在 URL 更改时重新加载。

【讨论】:

执行 $location.search 后如何获取新的搜索参数?执行 $location.search 之后,似乎 $stateParams 没有更新,并且 $routeParams 没有新值。 @DownChapel 我非常想了解自己 @DownChapel 你必须在你的控制器中监听 $locationChangeStart 并且你可以使用 $location.search() 来获取当前的查询参数【参考方案2】:

2015 年 5 月 19 日更新

从 ui-router 0.2.15 开始,已解决查询参数更改时重新加载状态的问题。然而,新的更新打破了历史 API 使用查询参数的向后和转发功能。我还没有找到解决方法。

原创

Jay 的回答对我不起作用,很多其他答案也没有。尝试收听$locationChangeStart 会导致在浏览器历史记录中来回切换时出现问题,因为这会导致我运行代码两次:一次是在新状态发生变化时,另一次是因为$loationChangeStart 被触发。

我尝试使用reloadOnSearch=false,但即使 url 路径发生更改,prevented state changes 也是如此。所以我终于通过以下方式让它工作了:

当您更改$location.search() 以更新查询参数时,使用"hack" 暂时禁用搜索重新加载,设置查询参数,然后重新启用重新加载。

$state.current.reloadOnSearch = false;

$location.search('query', [1,2]);

$timeout(function () 
  $state.current.reloadOnSearch = undefined;
);

这将确保查询参数更改不会重新加载状态,并且 url 路径更改将正确重新加载状态。

但是,当查询参数是 url 的一部分时,这并没有让浏览器历史记录更改状态(需要知道查询参数何时更改以重新读取 URL)。所以我还必须将每个查询参数的名称添加到state 的url 属性中。

$locationProvider.html5Mode(true);

$stateProvider
  .state('home', 
    url: '/?param1&param2&param3',
    templateUrl: 'home.html',
    controller: 'homeCtrl as home',
  );

以这种方式列出时,url 上的任何参数名称都是可选的,但是对这些参数名称的任何更改都会在点击浏览器上的后退和前进按钮时重新加载状态。

希望其他人发现这很有用,并且他们不需要花费数天时间来弄清楚如何去做(就像我一样)。

【讨论】:

我很生气,我没有早点找到这个。我设计了一个完整的应用程序来处理这个错误和所涉及的黑客行为。我刚刚将您的 reloadOnSearch hack 实现为一个不错的方法,并且效果很好。干得好。 这是没有任何副作用的正确答案。做得好!简单易行。 我做了类似的事情,但是遇到了 $stateParams 的值被注入解析的问题。至少在 0.2.15 中,URL 中已更改的参数在从子状态转换回父状态时(至少在通过 $stateParams 提供到解析时)将恢复为之前的值。跨度> 这对我不起作用。最近有人在 Angular 1.6 上测试过吗? 这是一个 hack,但适用于 angular 1.8.0 + ui-router 1.0.27 包括历史。 if ($state.$current.navigable.params.hasOwnProperty('tab')) $state.$current.navigable.params['tab'].dynamic = true; $location.search(locationSearch); $timeout(function () currentState.reloadOnSearch = reloadOnSearchBefore; if ($state.$current.navigable.params.hasOwnProperty('tab')) $state.$current.navigable.params['tab'].dynamic = false; );【参考方案3】:

在更新到 ui-router 0.2.14 之前,我遇到了 .transitionTo 的问题。 0.2.14 使用如下调用正确更改地址栏(无需重新加载控制器):

$state.transitionTo('search', q: 'updated search term',  notify: false );

【讨论】:

最佳答案,最不老套 终于有用了!谢谢@pmont,我在参数中使用了 dynamic: true ,但它不仅不能始终如一地工作,如果我按照你的方法甚至没有必要。 这就是我一直在寻找的甜美短片。 $state.go 在内部调用$state.transitionTo,但自动将选项设置为 location: true, inherit: true, relative: $state.$current, notify: true 。这使您可以轻松地使用绝对路径或相对路径,并仅指定您要更新的参数(同时让未指定的参数从当前状态继承。 但是当我使用这个解决方案时,它似乎会重新加载组件。我正在使用最新的 Angular UI 路由器 1.0.0.beta3

以上是关于使用 Angular ui-router 设置 URL 查询参数而不改变状态的主要内容,如果未能解决你的问题,请参考以下文章

angular ui-router怎么使用

Angular 2、TypeScript 和 ui-router - 如何获取状态参数

将 Angular UI-Router 与 Phonegap 一起使用

angular ui-router 1.0.3 和 angular.js 1.6.4 似乎使用了错误的 Promise 类型?

Angular 没有使用 ui-router 响应任何路由 - 当我输入时 URL 就会消失

有啥方法可以查看使用 Angular UI-Router 的网页的完整源代码?