>情况:
在我的 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 路径和搜索段,而不是它们的哈希爆炸等效项。