如何使用角度检测浏览器后退按钮单击事件?

IT技术 javascript jquery angularjs
2021-01-23 23:38:27

是否可以检测到用户通过使用浏览器中的历史后退按钮进入了页面?最好我想使用 angular.js 检测这个动作。

我不想使用角度路由。如果用户提交表单并在成功提交到服务器并重定向后,它也应该可以工作,如果用户使用浏览器的后退按钮返回表单也应该是可能的。

6个回答

这是 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 没有被触发,这意味着用户已经使用了历史记录。

上面的代码不会检测 URL 查询字符串更改,例如 from /#/news/?page=2to /#/news/?page=3要捕获这些,您也可以使用$location.absUrl()代替$location.path()(在上面使用它的两个地方)。
2021-03-17 23:38:27
对于不了解其工作原理的任何人(如我):当 url 以通常方式更改时(不使用后退/前进按钮),然后回调$locationChangeSuccess触发事件但是当使用后退/前进按钮或api更改 url 时,则回调之前触发事件所以当手表回调触发已经等于. 这就是 angular 在内部的工作方式,而这个解决方案只是使用了这种内部行为。 $watchhistory.back()$locationChangeSuccess $watchactualLocationnewLocation
2021-03-21 23:38:27
谢谢!看起来很棒。明天必须详细检查。特别是我必须检查 $rootScope.actualLocation 是否也更新,如果位置改变而不使用角度路线,而是“正常”超链接。你认为它也可以使用普通的超链接吗?
2021-04-01 23:38:27
没错。以前从未使用过角度路线,所以看看你的例子,似乎没有正常和不正常(角度路线类型)的超链接。所以忘了我的评论..
2021-04-09 23:38:27
$locationProvider.html5Mode(true) 仅用于使链接在 jsFiddle 中工作,您的项目中不需要它。请记住链接需要以 #/ 开头,以便 angular 可以捕获它们(在小提琴中它们不是)。如果您使用“普通”链接,例如 /book,angular 将不会捕获它并且页面将被重定向到该 url,这将重置您的应用程序,因为所有脚本都将重新加载,这就是它不起作用的原因.
2021-04-09 23:38:27

如果您想要更精确的解决方案(检测前后检测),我扩展了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;
    });
这不会检测后退按钮的点击——这只是检测用户是否在两个状态名称之间切换——要么通过后退按钮,要么通过在两个页面之间点击。此外,这不看状态的参数。
2021-03-17 23:38:27

我知道这是一个老问题。无论如何 :)

Bema 的回答看起来很棒。但是,如果您想让它与“普通”网址一起使用(我猜没有哈希),您可以比较绝对路径,而不是由以下返回的路径$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/en-US/docs/DOM/window.history?redirectlocale=en-US&redirectslug=window.history

不确定它在多浏览器支持方面有多好。

更新

似乎我上面所说的仅适用于 Gecko 类型的浏览器。

对于其他浏览器尝试使用history.js; https://github.com/browserstate/history.js

谢谢你的评论。因为我更喜欢用 angular 来做这件事,所以我会尝试一下 Bertrands 的回答。
2021-03-16 23:38:27