각도를 사용하여 브라우저 뒤로 버튼 클릭 이벤트를 감지하는 방법은 무엇입니까?


79

사용자가 브라우저의 히스토리 뒤로 버튼을 사용하여 페이지에 들어온 것을 감지 할 수 있습니까? 바람직하게는 angular.js를 사용하여이 작업을 감지하고 싶습니다.

각도 라우팅을 사용하고 싶지 않습니다. 사용자가 양식을 제출하고 서버에 성공적으로 제출하고 리디렉션 한 후 브라우저의 뒤로 버튼을 사용하여 양식으로 돌아가는 경우에도 작동해야합니다.

답변:


120

다음은 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가 실행되지 않았기 때문에 사용자가 기록을 다시 사용했음을 의미합니다.


1
감사! 멋지네요. 내일 자세히 확인해야합니다. 특히 앵귤러 루트를 사용하지 않고 위치가 변경되면 $ rootScope.actualLocation도 업데이트되는지 확인해야합니다. 그러나 "일반"하이퍼 링크는 사용하지 않습니다. 일반 하이퍼 링크를 사용해도 작동 할 것이라고 생각하십니까?
Thomas Kremmel 2013-04-04

4
어 그래. 전에 각도 경로를 사용한 적이 없으므로 예를 보면 정상이 아닌 일반 (각 경로 유형) 하이퍼 링크가없는 것처럼 보입니다. 그래서 그냥 내 의견을 잊지 ..
토마스 Kremmel

2
$ locationProvider.html5Mode (true)는 링크가 jsFiddle에서 작동하도록 만드는 데만 사용되며 프로젝트에서는 필요하지 않습니다. 링크 앞에 # /가 있어야하므로 angular가 해당 링크를 캡처 할 수 있습니다 (바이올린에서는 그렇지 않음). / book, angular와 같은 "일반"링크를 사용하면 해당 링크가 캡처되지 않고 페이지가 해당 URL로 리디렉션됩니다. 모든 스크립트가 다시로드되기 때문에 앱이 재설정되므로 작동하지 않습니다. .
Bertrand

19
URL이 일반적인 방법으로 변경하는 경우 (/ 뒤로 감기 버튼을 사용하지 않는), 다음 : 어떻게 작동하는지 이해하지 못하는 (나 같은) 사람을 위해 $locationChangeSuccess이벤트 발사 $watch 콜백. 그러나 뒤로 / 앞으로 버튼 또는 history.back()API를 사용하여 URL을 변경하면 콜백 전에$locationChangeSuccess 이벤트가 발생 합니다. 따라서 시계 콜백 실행 이 이미 . angular가 내부적으로 작동하는 방식이며이 솔루션은이 내부 동작을 사용합니다. $watchactualLocationnewLocation
Ruslan Stelmachenko

5
위의 코드는에서 /#/news/?page=2로 와 같은 URL 쿼리 문자열 변경을 감지하지 않습니다 /#/news/?page=3. 그것들도 잡으려면 $location.absUrl()대신 사용할 수 있습니다 $location.path()(위에서 사용 된 두 곳에서).
Michael

11

보다 정확한 솔루션 (앞뒤로 감지)을 원한다면 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++;

        }

    }

 });

8

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

이것은 뒤로 버튼 클릭을 감지하지 않습니다. 이것은 사용자가 뒤로 버튼을 통해 또는 두 페이지 사이를 클릭하여 두 개의 상태 이름 사이를 전환하는지 감지합니다. 또한 이것은 상태의 매개 변수를 보지 않습니다.
Amy B

1

나는 그것이 오래된 질문이라는 것을 압니다. 어쨌든 :)

Bema의 대답은 훌륭해 보입니다. 그러나 '정상적인'URL (내가 추측하는 해시없이)으로 작동하게하려면 다음에서 반환 된 경로 대신 절대 경로를 비교할 수 있습니다 $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?');
        }
    });
});

0

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가 시도해 볼 것입니다.
Thomas Kremmel 2013-04-04

0

그래서 저는 @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 changed'코드를 모두 로컬 actualLocation변수 위에 닫을 수 있습니다. 거기에서 원래 코드 에서처럼 원하는대로 할 수 있습니다. 필자는 개별 컨트롤러가 필요한 모든 작업을 수행 할 수 있도록 이벤트를 브로드 캐스팅하는 것을 고려하지만 필요한 경우 전역 작업을 포함 할 수 있습니다 .

훌륭한 답변에 감사 드리며 이것이 다른 타이프 스크립트 사용자에게 도움이되기를 바랍니다.


-2

이 문제에 대한 나의 솔루션은

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

-7

뒤로 버튼을 누르면 angular는 $ routeChangeStart 이벤트 만 발생 하고 $ locationChangeStart 는 발생하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.