浏览器后退按钮在使用 Angular 的 $location.path() 更新后不会触发重新加载



>情况:

在我的 AngularJS 应用程序的一个视图上,我有两个分页按钮,它们使用 $http 来请求下一个和上一个数据。我使用的是ng-click="getNext(url)"而不是带有href="#/items/:itemId"的锚标签。我这样做的原因是我可以快速异步浏览我的内容,而不会触发页面重新加载。这很好用,但是使用此方法会绕过更新页面的URL,因此您的当前内容可能会与您的URL的ID不同步(即路径是#/items/3,但您当前正在查看项目9)。这可以通过使用 $location.path('items/' + rsp.id) 更新 JS 中的 URL 来轻松修复。现在我可以以异步方式获取数据,并且仍然能够刷新、添加书签、发送链接并显示正确/当前项目。

问题:

这样做的问题是,如果用户点击getNext()几次,然后尝试使用浏览器的后退按钮返回,则 URL 会像它应该的那样更新,但由于某种原因浏览器不执行刷新——它只是坐在那里并更新 URL。仅当历史记录中的项目来自同一视图并且我已使用位置服务更新了 ID 时,才会发生这种情况。

任何想法将不胜感激。

到目前为止我尝试过什么

承诺+旗帜

我一直在玩window.onpopstate,但到目前为止,我没有任何办法window.onpopstate区分浏览器单击和用$location.path()更新 URL 的 UI 单击;现在,无论来源如何,它都会触发事件。所以我尝试设置一个标志来假设每次触发此事件时都是浏览器事件,但是当它是基于 UI 的事件时,我可以禁用该标志,因为我的 _myRequestFn() 将处理它。即使有这个承诺设置,当_myRequestFn()被触发时,它仍然会触发window.onpopstate。

var flag = true; // Assume all requests are browser-based
    window.onpopstate = function() {
      if (flag) {
        $route.reload();
      }
      console.log('onpopstate fired');
    };
    _myRequestFn = function(id) {
        someService.getMyData(id)
          .then(function(rsp) {
           // Do a bunch of stuff including...
           $location.path('items/' + rsp.id);
           return rsp;
          })
          .then(function() {
             // Everything is done reset flag
             flag = true;
          });
    };
$scope.getNext(url) {
   flag = false;
   _myRequestFn(url);
};

欺骗

返回

#/item/5> #/item/4> #/item/3 只会更新 URL 而不是路径,但如果历史记录具有不同的参数 #/thing/2> #/item/2 会触发页面刷新。由于如果历史记录来自不同的参数,浏览器后退按钮会起作用,我想看看我是否加载了不同的参数,它会起作用。因此,我创建了一个 #/item-a 和 #/item-b 路由,它们加载相同的模板并使用相同的控制器,只是在每个请求中从 a/b 切换。我永远不会向某人推荐此解决方案,我只是看看是否可以触发刷新。

更新IRC上的很多人都建议我使用UI-Router。我真的在尝试使用开箱即用的 Angular 解决方案。重构我的整个路由设置以使用 UI-Router 并不是最佳解决方案。

app.config(['$locationProvider',
    function($locationProvider) {
       // Enable html5 mode
       $locationProvider.html5Mode(true);
    }]);

从文档中:

在 HTML5 模式下,$location 服务获取者和资源库通过 HTML5 历史记录 API 与浏览器 URL 地址进行交互。这允许使用常规 URL 路径和搜索段,而不是它们的哈希爆炸等效项。

最新更新