새 페이지에서 경로를 변경해도 맨 위로 스크롤되지 않습니다


271

나는 경로가 바뀔 때 적어도 나에게 바람직하지 않은 행동을 발견했습니다. 자습서 http://angular.github.io/angular-phonecat/step-11/app/#/phones의 11 단계 에서 전화 목록을 볼 수 있습니다. 맨 아래로 스크롤하여 최신 중 하나를 클릭하면 스크롤이 맨 위에 있지 않고 대신 중간에 있음을 알 수 있습니다.

내 응용 프로그램 중 하나에서도 이것을 발견했으며 어떻게 이것을 맨 위로 스크롤 할 수 있는지 궁금했습니다. 나는 그것을 수동으로 할 수 있지만, 나는 모르는 다른 우아한 방법이 있어야한다고 생각합니다.

경로가 바뀔 때 맨 위로 스크롤하는 우아한 방법이 있습니까?

답변:


578

문제는 ngView 가 새보기를로드 할 때 스크롤 위치를 유지 한다는 것 입니다. $anchorScroll"보기가 업데이트 된 후 뷰포트를 스크롤" 하도록 지시 할 수 있습니다 ( 문서 는 약간 모호하지만 여기서 스크롤 하면 새보기 의 맨 위로 스크롤하는 것을 의미 합니다).

해결책autoscroll="true"ngView 요소 에 추가 하는 것입니다.

<div class="ng-view" autoscroll="true"></div>

1
이 작업은 페이지 스크롤을 맨 위로 스크롤하지만 smoothScroll 지시문과 함께 scrollTo를 사용하고 있습니다. 스무스 스크롤을 맨 위로 스크롤하는 방법이 있습니까? 또한 솔루션이 페이지가 아닌 맨 위로 스크롤하여 스크롤 할 수 있습니다 페이지 상단?
xzegga

19
문서 상태 속성이 값없이 설정되면 scrolling을 활성화하십시오 . 따라서 코드를 짧게 단축 할 수 있으며 <div class="ng-view" autoscroll></div>스크롤을 조건부로 만들지 않는 한 동일하게 작동합니다.
Daniel Liuzzi

7
그것은 나를 위해 작동하지 않습니다, 의사는 상단으로 스크롤한다고 말하지 않습니다
Pencilcheck

6
자동 스크롤이 true로 설정된 경우 사용자가 '돌아 가면'페이지를 떠난 곳이 아니라 페이지의 맨 위로 돌아갑니다. 이는 바람직하지 않은 동작입니다.
axzr

4
뷰를이 div로 스크롤합니다. 따라서 페이지 상단에있는 경우에만 페이지 상단으로 스크롤됩니다. 그렇지 않으면 $window.scrollTo(0,0)$ stateChangeSuccess 이벤트 리스너에서 실행해야합니다.
Filip Sobczak

46

이 코드를 실행하십시오.

$rootScope.$on("$routeChangeSuccess", function (event, currentRoute, previousRoute) {

    window.scrollTo(0, 0);

});

6
$window.scrollTop(0,0)자동 스크롤보다 나에게 더 효과적입니다. 제 경우에는 전환으로 들어오고 나가는 뷰가 있습니다.
IsidroGH

1
이것은 autoscroll = "true"보다 나에게 더 효과적입니다. 어떤 이유로 자동 스크롤이 너무 늦어서 새보기가 이미 표시된 후 맨 위로 스크롤됩니다.
Gregory Bolkenstijn 2016 년

5
이것은 나에게 가장 효과적이었다 : $ rootScope. $ on ( '$ stateChangeSuccess', function () {$ ( "html, body"). animate ({scrollTop : 0}, 200);});
James Gentes

$ window.scrollTop은 $ window.scrollTo 여야하며, 그렇지 않으면 존재하지 않는다고 표시됩니다. 이 솔루션은 훌륭하게 작동합니다!
소프트웨어 예언자

@JamesGentes 나는 이것도 필요했다. 감사.
Mackenzie Browne

36

이 코드는 저에게 효과적이었습니다. .. 저에게도 효과가 있기를 바랍니다. .. 실행 블록에 $ anchorScroll을 주입하고 아래 예제에서했던 것처럼 리스너 함수를 rootScope에 적용하기 만하면됩니다.

 angular.module('myAngularApp')
.run(function($rootScope, Auth, $state, $anchorScroll){
    $rootScope.$on("$locationChangeSuccess", function(){
        $anchorScroll();
    });

Angularjs 모듈의 호출 순서는 다음과 같습니다.

  1. app.config()
  2. app.run()
  3. directive's compile functions (if they are found in the dom)
  4. app.controller()
  5. directive's link functions (again, if found)

RUN BLOCK 은 인젝터가 생성 된 후 실행되어 응용 프로그램을 킥 스타트하는 데 사용됩니다. 이는 새 경로보기로 리디렉션 될 때 실행 블록의 리스너가

$ anchorScroll ()

이제 새로운 라우팅 뷰로 스크롤이 맨 위로 시작하는 것을 볼 수 있습니다. :)


마지막으로, 스티커 헤더와 함께 작동하는 솔루션! 감사합니다!
Fabio

31

의 모든 조합을 시도 한 두 시간 후 ui-view autoscroll=true, $stateChangeStart, $locationChangeStart, $uiViewScrollProvider.useAnchorScroll(), $provide('$uiViewScroll', ...)예상대로, 그리고 많은 다른 사람을, 나는 스크롤 - 투 - 톱에 새로운 페이지 작업을 가져올 수 없습니다.

이것이 궁극적으로 저에게 효과적이었습니다. pushState 및 replaceState를 캡처하고 새 페이지를 탐색 할 때만 스크롤 위치를 업데이트합니다 (뒤로 / 앞으로 버튼으로 스크롤 위치 유지).

.run(function($anchorScroll, $window) {
  // hack to scroll to top when navigating to new URLS but not back/forward
  var wrap = function(method) {
    var orig = $window.window.history[method];
    $window.window.history[method] = function() {
      var retval = orig.apply(this, Array.prototype.slice.call(arguments));
      $anchorScroll();
      return retval;
    };
  };
  wrap('pushState');
  wrap('replaceState');
})

이것은 내 유스 케이스에 효과적입니다. 중첩 된 뷰 (여러 수준의 깊이)가있는 Angular UI-Router를 사용하고 있습니다. 감사!
Joshua Powell

참고 $locationProvider.html5Mode(true); -pushState 를 사용하려면 각도에서 HTML5 모드에 있어야합니다. @ wkronkel 각도에서 HTML5 모드를 사용 하지 않을 때 이것을 수행하는 방법이 있습니까? HTML 5 모드가 활성화되어 페이지 다시로드시 404 오류가 발생 함
britztopher

@britztopher 당신은 내장 이벤트에 연결하고 자신의 역사를 유지할 수 있습니다.
Casey

2
이것을 어디에 추가 .run합니까? 각도 app개체?
Philll_t

1
@Philll_t : 예, run함수는 모든 각도 모듈 객체에서 사용할 수있는 방법입니다.
Hinrich

18

여기에 (견고하게) 강력하고 완전하며 (공정하게) 간결한 솔루션이 있습니다. 축소 호환 스타일과 모듈에 대한 angular.module (NAME) 액세스를 사용합니다.

angular.module('yourModuleName').run(["$rootScope", "$anchorScroll" , function ($rootScope, $anchorScroll) {
    $rootScope.$on("$locationChangeSuccess", function() {
                $anchorScroll();
    });
}]);

추신 : 나는 자동 스크롤이 true 또는 false로 설정되었는지 여부에 영향을 미치지 않는다는 것을 알았습니다.


1
흠 ..이 스크롤 가기보기 첫번째 다음 나를 위해 화면의보기 변경됩니다.
Strelok

내가 찾고있는 깨끗한 솔루션. "뒤로"를 클릭하면 중단 한 곳으로 이동합니다. 일부에게는 바람직하지 않을 수도 있지만 제 경우에는 마음에들 것입니다.
mjoyce91

15

angularjs UI 라우터를 사용하여 내가하고있는 일은 다음과 같습니다.

    .state('myState', {
        url: '/myState',
        templateUrl: 'app/views/myState.html',
        onEnter: scrollContent
    })

와:

var scrollContent = function() {
    // Your favorite scroll method here
};

어떤 페이지에서도 실패하지 않으며 전역이 아닙니다.


1
좋은 생각, 당신은 그것을 사용하여 더 짧게 만들 수 있습니다 :onEnter: scrollContent
zucker

2
당신이 쓴 곳에 무엇을 넣 // Your favorite scroll method here습니까?
에이전트 Zebra

4
좋은 타이밍 : 원래 코드에서 ui-router-title을 시도 하여이 주석보다 두 줄 위에있었습니다 . 사용합니다 $('html, body').animate({ scrollTop: -10000 }, 100);
Léon Pelletier

1
하하! 이상한 tho, 그것은 항상 나를 위해 작동하지 않습니다. 나는 너무 짧아서 스크롤이없는 두 개의 뷰와 스크롤이있는 두 개의 뷰가 있는데, onEnter: scrollContent각 뷰에 배치 할 때 두 번째 뷰가 아닌 첫 번째 뷰 / 경로에서만 작동합니다. 이상한.
에이전트 Zebra

1
잘 모르겠습니다. 아니요, 스크롤해야 할 때 맨 위로 스크롤하지 않습니다. '라우트'사이를 클릭하면 일부는 여전히 페이지의 절대 상단이 아니라 ng-view가있는 곳으로 스크롤됩니다. 말이 돼?
에이전트 Zebra

13

참고로 AngularUI Router 플러그인을 사용하는 제목에 설명 된 문제를 겪는 사람에게도 참고하십시오 ...

이 SO 질문에서 묻고 대답 한 것처럼 angular-ui 라우터는 경로를 변경할 때 페이지의 맨 아래로 이동합니다.
페이지가 왜 맨 아래에로드되는지 알 수 없습니까? 각도 UI 라우터 자동 스크롤 문제

그러나 답변에 나와있는 것처럼에 말하여이 동작을 해제 할 수 autoscroll="false"있습니다 ui-view.

예를 들면 다음과 같습니다.

<div ui-view="pagecontent" autoscroll="false"></div>
<div ui-view="sidebar" autoscroll="false"></div> 

http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.directive:ui-view


16
광산은 맨 아래로 이동하지 않고 맨 위로 이동하는 대신 스크롤 위치를 유지합니다.
Stephen Smith

5
이것은 질문에 대답하지 않습니다. 경로가 변경되면 스크롤 수준이 맨 위로 스크롤하는 대신 동일한 위치에 유지됩니다. 상단으로 스크롤 할 수는 있지만 해시를 변경해야 만합니다. 명백한 이유로하고 싶지 않습니다.
Will

7

이 자바 스크립트를 사용할 수 있습니다

$anchorScroll()

3
글쎄, 그것은 angularjs에서 그렇게 간단하지 않습니다. 귀하의 솔루션은 jquery에서만 유효합니다. 내가 찾는 것은 angularjs에서이를 수행 하는 우아한 방법입니다
Matias Gonzalez

4
$ anchorScroll ()을 사용해 보셨습니까? docs.angularjs.org/api/ng.%24anchorScroll 문서화 되어 있습니다.
CodeIsLife

1
당신과 위치를 지정 참고하면 $location.hash('top')전에 $anchorScroll()앞으로 기본 / 다시 브라우저 버튼 더 이상 작동하지 않습니다; 그들은 URL의 해시로 계속 리디렉션합니다
Roy

7

ui-router를 사용하면 (실행시) 사용할 수 있습니다

$rootScope.$on("$stateChangeSuccess", function (event, currentState, previousState) {
    $window.scrollTo(0, 0);
});

이것이 작동해야한다는 것을 알고 있습니다. 광범위하게 "$ stateChangeSuccess"를 사용하고 있지만 어떤 이유로 $ window.scrollTo (0,0)이 작동하지 않습니다.
Abhas

4

이 솔루션을 찾았습니다. 새로운보기로 이동하면 기능이 실행됩니다.

var app = angular.module('hoofdModule', ['ngRoute']);

    app.controller('indexController', function ($scope, $window) {
        $scope.$on('$viewContentLoaded', function () {
            $window.scrollTo(0, 0);
        });
    });

3

autoScroll을 true로 설정하는 것은 속임수가 아니므로 다른 솔루션을 선택했습니다. 나는 경로가 바뀔 때마다 연결되고 내장 된 $ anchorScroll 서비스를 사용하여 맨 위로 스크롤하는 서비스를 만들었습니다. 나를 위해 작동 :-).

서비스:

 (function() {
    "use strict";

    angular
        .module("mymodule")
        .factory("pageSwitch", pageSwitch);

    pageSwitch.$inject = ["$rootScope", "$anchorScroll"];

    function pageSwitch($rootScope, $anchorScroll) {
        var registerListener = _.once(function() {
            $rootScope.$on("$locationChangeSuccess", scrollToTop);
        });

        return {
            registerListener: registerListener
        };

        function scrollToTop() {
            $anchorScroll();
        }
    }
}());

기재:

angular.module("mymodule").run(["pageSwitch", function (pageSwitch) {
    pageSwitch.registerListener();
}]);

3

파티에 조금 늦었지만 가능한 모든 방법을 시도했지만 아무것도 제대로 작동하지 않았습니다. 내 우아한 해결책은 다음과 같습니다.

ui-router로 모든 페이지를 관리하는 컨트롤러를 사용합니다. 인증 또는 검증되지 않은 사용자를 적절한 위치로 리디렉션 할 수 있습니다. 대부분의 사람들은 앱 구성에 미들웨어를 넣었지만 http 요청이 필요했기 때문에 글로벌 컨트롤러가 더 잘 작동합니다.

내 index.html은 다음과 같습니다.

<main ng-controller="InitCtrl">
    <nav id="top-nav"></nav>
    <div ui-view></div>
</main>

내 initCtrl.js는 다음과 같습니다.

angular.module('MyApp').controller('InitCtrl', function($rootScope, $timeout, $anchorScroll) {
    $rootScope.$on('$locationChangeStart', function(event, next, current){
        // middleware
    });
    $rootScope.$on("$locationChangeSuccess", function(){
        $timeout(function() {
            $anchorScroll('top-nav');
       });
    });
});

가능한 모든 옵션을 시도했지만이 방법이 가장 효과적입니다.


1
이것은 나를 위해 각도 재료로 작업 한 유일한 id="top-nav"요소이며 올바른 요소에 배치하는 것이 중요했습니다.
BatteryAcid

2

위의 모든 답변은 예상되는 브라우저 동작을 위반합니다. 대부분의 사람들이 원하는 것은 "새"페이지 인 경우 맨 위로 스크롤하지만 뒤로 (또는 앞으로) 버튼을 통해 도착하면 이전 위치로 돌아가는 것입니다.

HTML5 모드를 가정한다면, 이것은 쉬운 것으로 판명되었습니다 (그러나 일부 밝은 사람들은 이것을 더 우아하게 만드는 방법을 알아낼 수 있다고 확신합니다!) :

// Called when browser back/forward used
window.onpopstate = function() { 
    $timeout.cancel(doc_scrolling); 
};

// Called after ui-router changes state (but sadly before onpopstate)
$scope.$on('$stateChangeSuccess', function() {
    doc_scrolling = $timeout( scroll_top, 50 );

// Moves entire browser window to top
scroll_top = function() {
    document.body.scrollTop = document.documentElement.scrollTop = 0;
}

그것이 작동하는 방식은 라우터가 상단으로 스크롤한다고 가정하지만 브라우저가 완료 될 수 있도록 약간 지연시킵니다. 브라우저가 변경 내용이 뒤로 / 앞으로 탐색으로 인한 것임을 알리면 시간 초과가 취소되고 스크롤이 발생하지 않습니다.

document창 상단 전체로 이동하고 싶기 때문에 원시 명령을 사용 하여 스크롤했습니다. ui-view스크롤 만하 려면 위의 기술을 사용하여 autoscroll="my_var"제어 할 위치 를 설정 my_var하십시오. 그러나 "신규"페이지로 이동하면 대부분의 사람들이 전체 페이지를 스크롤하려고한다고 생각합니다.

위의 사용 UI 라우터, 당신 불구 대신 교환에 의해 겨-경로를 사용할 수 $routeChangeSuccess에 대한 $stateChangeSuccess.


이것을 어떻게 구현합니까? 다음과 같은 일반 앵귤러 UI 경로 코드에서 어디에 배치 하시겠습니까? var routerApp = angular.module('routerApp', ['ui.router']); routerApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) { $urlRouterProvider.otherwise('/home'); $locationProvider.html5Mode(false).hashPrefix(""); $stateProvider // HOME STATES AND NESTED VIEWS ======================================== .state('home', { url: '/home', templateUrl: 'partial-home.html' }) });
에이전트 Zebra

흠 ...하지 작업 :-( 그냥 응용 프로그램을 죽이고했다. .state('web', { url: '/webdev', templateUrl: 'partial-web.html', controller: function($scope) { $scope.clients = ['client1', 'client2', 'client3']; // I put it here } }) 난 그냥 어쩌면 내가 모르는 뭔가가있어,이 물건을 배우는 중이에요 : D
에이전트 얼룩말

@AgentZebra 최소한 컨트롤러는 $ timeout을 입력으로 사용해야합니다 (코드가 참조하기 때문에). 더 중요한 것은 언급 한 컨트롤러가 개별 상태보다 높은 레벨에 있어야한다는 것입니다. 최상위 컨트롤러에 명령문을 포함시킬 수 있습니다). 초기 AngularJS 학습 곡선은 실제로 매우 어렵습니다. 행운을 빕니다!
Dev93

2

제공된 답변 중 어느 것도 내 문제를 해결하지 못했습니다. 뷰 사이에 애니메이션을 사용하고 있으며 애니메이션 후 항상 스크롤이 발생합니다. 내가 찾은 해결책은 애니메이션이 스크롤되기 전에 맨 위로 스크롤하는 것이 다음 지시문입니다.

yourModule.directive('scrollToTopBeforeAnimation', ['$animate', function ($animate) {
    return {
        restrict: 'A',
        link: function ($scope, element) {
            $animate.on('enter', element, function (element, phase) {

                if (phase === 'start') {

                    window.scrollTo(0, 0);
                }

            })
        }
    };
}]);

다음과 같이 내 견해에 삽입했습니다.

<div scroll-to-top-before-animation>
    <div ng-view class="view-animation"></div>
</div>

2

간단한 해결책, scrollPositionRestoration활성화 된 기본 경로 모듈에 추가하십시오 .
이처럼 :

const routes: Routes = [

 {
   path: 'registration',
   loadChildren: () => RegistrationModule
},
];

 @NgModule({
  imports: [
   RouterModule.forRoot(routes,{scrollPositionRestoration:'enabled'})
  ],
 exports: [
 RouterModule
 ]
 })
  export class AppRoutingModule { }


0

마침내 내가 필요한 것을 얻었습니다.

맨 위로 스크롤해야했지만 일부 전환이 필요하지 않았습니다.

경로별로 라우팅 레벨에서이를 제어 할 수 있습니다.
@wkonkel에 의해 위의 솔루션을 결합하고 noScroll: true일부 경로 선언에 간단한 매개 변수를 추가 합니다. 그런 다음 전환에서 그것을 잡았습니다.

전체적으로 : 이것은 새로운 전환에서 페이지의 상단으로 이동하고, 전환 시 Forward/ 상단으로 Back이동 하지 않으며 필요한 경우이 동작을 무시할 수 있습니다.

코드 : (이전 솔루션 및 추가 noScroll 옵션)

  // hack to scroll to top when navigating to new URLS but not back/forward
  let wrap = function(method) {
    let orig = $window.window.history[method];
    $window.window.history[method] = function() {
      let retval = orig.apply(this, Array.prototype.slice.call(arguments));
      if($state.current && $state.current.noScroll) {
        return retval;
      }
      $anchorScroll();
      return retval;
    };
  };
  wrap('pushState');
  wrap('replaceState');

그것을 당신의 app.run블록에 넣고 주입하십시오 $state...myApp.run(function($state){...})

그런 다음 페이지 상단으로 스크롤하지 않으려면 다음과 같이 경로를 만드십시오.

.state('someState', {
  parent: 'someParent',
  url: 'someUrl',
  noScroll : true // Notice this parameter here!
})

0

이것은 자동 스크롤을 포함하여 나를 위해 일했습니다.

<div class="ngView" autoscroll="true" >

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