是否可以通过使用浏览器中的历史记录后退按钮检测到用户输入了页面?最好是我想使用angular.js检测到此动作。
我不想使用角度布线。如果用户提交表单,并且在成功提交到服务器并进行重定向之后,它也应该起作用,如果用户使用浏览器的“后退”按钮返回到表单,也应该可行。
Answers:
这是Angular的解决方案。
myApp.run(function($rootScope, $route, $location){
//Bind the `$locationChangeSuccess` event on the rootScope, so that we dont need to
//bind in induvidual controllers.
$rootScope.$on('$locationChangeSuccess', function() {
$rootScope.actualLocation = $location.path();
});
$rootScope.$watch(function () {return $location.path()}, function (newLocation, oldLocation) {
if($rootScope.actualLocation === newLocation) {
alert('Why did you use history back?');
}
});
});
我正在使用运行块来启动它。首先,我将实际位置存储在$ rootScope.actualLocation中,然后侦听$ locationChangeSuccess,并在发生这种情况时使用新值更新ActualLocation。
在$ rootScope中,我监视位置路径中的更改,以及新位置是否与previousLocation相等,这是因为未触发$ locationChangeSuccess,这意味着用户已使用了历史记录。
$locationChangeSuccess
触发事件。但是,当使用后退/前进按钮或api更改网址时,则会在回调之前触发事件。因此,当watch回调触发时已经等于。正是角度内部如何工作,此解决方案仅使用了这种内部行为。 $watch
history.back()
$locationChangeSuccess
$watch
actualLocation
newLocation
/#/news/?page=2
到/#/news/?page=3
。为了捕捉这些,您可以使用$location.absUrl()
代替$location.path()
(在上面使用的两个地方)。
如果您想要更精确的解决方案(前后检测),我可以扩展Bertrand提供的解决方案:
$rootScope.$on('$locationChangeSuccess', function() {
$rootScope.actualLocation = $location.path();
});
$rootScope.$watch(function () {return $location.path()}, function (newLocation, oldLocation) {
//true only for onPopState
if($rootScope.actualLocation === newLocation) {
var back,
historyState = $window.history.state;
back = !!(historyState && historyState.position <= $rootScope.stackPosition);
if (back) {
//back button
$rootScope.stackPosition--;
} else {
//forward button
$rootScope.stackPosition++;
}
} else {
//normal-way change of page (via link click)
if ($route.current) {
$window.history.replaceState({
position: $rootScope.stackPosition
});
$rootScope.stackPosition++;
}
}
});
对于ui路由,我使用以下代码。
内部App.run()
使用
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams)
{
if (toState.name === $rootScope.previousState )
{
// u can any 1 or all of below 3 statements
event.preventDefault(); // to Disable the event
$state.go('someDefaultState'); //As some popular banking sites are using
alert("Back button Clicked");
}
else
$rootScope.previousState= fromState.name;
});
如果需要,您也可以在'$ stateChangeSuccess'事件中获取'previousState'值,如下所示。
$rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams)
{
$rootScope.previousStatus = fromState.name;
});
我知道这是一个老问题。无论如何 :)
贝玛的答案很好看。但是,如果您想使其与“普通”网址一起使用(我想没有哈希值),则可以比较绝对路径,而不是$location.path()
:
myApp.run(function($rootScope, $route, $location){
//Bind the `$locationChangeSuccess` event on the rootScope, so that we dont need to
//bind in induvidual controllers.
$rootScope.$on('$locationChangeSuccess', function() {
$rootScope.actualLocation = $location.absUrl();
});
$rootScope.$watch(function () {return $location.absUrl()}, function (newLocation, oldLocation) {
if($rootScope.actualLocation === newLocation) {
alert('Why did you use history back?');
}
});
});
JavaScript具有本机历史对象。
window.history
检查MDN以获取更多信息;https://developer.mozilla.org/zh-CN/docs/DOM/window.history?redirectlocale=zh-CN&redirectslug=window.history
不知道它在多浏览器支持上的表现如何。
更新资料
看来我上面所说的仅适用于Gecko型浏览器。
对于其他浏览器尝试使用history.js
; https://github.com/browserstate/history.js
因此,我已经将@Bema的答案转录为TypeScript,结果如下所示:
namespace MyAwesomeApp {
// ReSharper disable once Class
function detectBackButton(
$rootScope: ng.IRootScopeService,
$location: ng.ILocationService
) {
let actualLocation: string = '';
$rootScope.$on('$locationChangeSuccess',
() => {
actualLocation = $location.path();
});
$rootScope.$watch(() => $location.path(),
(newLocation: string, oldLocation: string) => {
if (actualLocation === newLocation) {
//$rootScope.$broadcast('onBackButtonPressed', null);
}
});
}
detectBackButton.$inject = [
'$rootScope',
'$location'
];
angular
.module('app')
.run(detectBackButton);
}
我们不必在$rootScope
服务之外创建属性,我们只需使“ on location change success”(成功更改位置)和“ on location changes”(更改位置)代码都靠近局部actualLocation
变量即可。从那里,您可以按照自己的意愿做任何事情,就像原始代码一样。就我而言,我会考虑在播放事件使个别控制器可以为所欲为必须的,但你可以包括全球行动,如果你要。
感谢您的出色回答,希望对其他打字稿用户有所帮助。
我对这个问题的解决方案是
app.run(function($rootScope, $location) {
$rootScope.$on('$locationChangeSuccess', function() {
if($rootScope.previousLocation == $location.path()) {
console.log("Back Button Pressed");
}
$rootScope.previousLocation = $rootScope.actualLocation;
$rootScope.actualLocation = $location.path();
});
});