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

Posted

技术标签:

【中文标题】如何使用角度检测浏览器后退按钮单击事件?【英文标题】:How to detect browser back button click event using angular? 【发布时间】:2013-03-26 16:24:03 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

所以,我已经将@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 服务之外创建属性,我们只需将“位置更改成功”和“位置更改”代码都关闭在本地actualLocation 变量上。从那里,您可以做任何您喜欢的事情,就像在原始代码中一样。就我而言,我会考虑广播一个事件,以便各个控制器可以做他们必须做的任何事情,但你可以包括全局操作如果你不得不

感谢您的出色回答,我希望这对其他打字稿用户有所帮助。

【讨论】:

【参考方案2】:

这是一个使用 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,当它发生时,我使用新值更新实际位置。

在 $rootScope 中,我观察位置路径的变化,如果新位置等于 previousLocation 是因为 $locationChangeSuccess 没有被触发,这意味着用户已经使用了历史记录。

【讨论】:

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

对于 ui-routing,我使用下面的代码。

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;
    );

【讨论】:

这不会检测后退按钮的点击——这只是检测用户是否在两个状态名称之间切换——无论是通过后退按钮,还是通过在两个页面之间单击。这也不看状态的参数。【参考方案4】:

我对这个问题的解决方案是

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();
    );
);

【讨论】:

【参考方案5】:

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

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?');
        
    );
);

【讨论】:

【参考方案6】:

如果您想要更精确的解决方案(前后检测),我扩展了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++;

        

    

 );

【讨论】:

【参考方案7】:

当按下返回按钮时,angular 只会触发 $routeChangeStart 事件,$locationChangeStart 不会触发。

【讨论】:

【参考方案8】:

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

【讨论】:

感谢您的评论。由于我更喜欢​​有角度的方法,所以我会尝试一下 Bertrands 的回答。

以上是关于如何使用角度检测浏览器后退按钮单击事件?的主要内容,如果未能解决你的问题,请参考以下文章

Javascript/jQuery 仅在浏览器后退/前进按钮单击时检测哈希更改

如何知道Firefox中是否单击了刷新按钮或浏览器后退按钮[重复]

单击浏览器的后退按钮时如何销毁会话

在rails 5中单击浏览器的后退按钮后如何避免返回?

使用浏览器后退按钮时如何强制重新加载页面?

如何使浏览器后退按钮跳过内页导航并返回上一页