Angular 5 클릭 할 때마다 맨 위로 스크롤


99

앵귤러 5를 사용하고 있습니다. 작은 콘텐츠가있는 섹션이 거의없고 콘텐츠가 너무 큰 섹션이 거의 없어 맨 위로 이동하는 동안 라우터를 변경할 때 문제가 발생하는 대시 보드가 있습니다. 맨 위로 가기 위해 스크롤해야 할 때마다. 누구든지 라우터를 변경할 때 내 시야가 항상 맨 위에 있도록이 문제를 해결하도록 도와 줄 수 있습니까?

미리 감사드립니다.


답변:


211

몇 가지 해결책이 있습니다. 모두 확인하십시오. :)

라우터 아울렛은 activate새 구성 요소가 인스턴스화 될 때마다 이벤트 를 방출 하므로 (activate)(예를 들어) 맨 위로 스크롤 하는 데 사용할 수 있습니다 .

app.component.html

<router-outlet (activate)="onActivate($event)" ></router-outlet>

app.component.ts

onActivate(event) {
    window.scroll(0,0);
    //or document.body.scrollTop = 0;
    //or document.querySelector('body').scrollTo(0,0)
    ...
}

또는 이 답변 을 사용하여 부드러운 스크롤

    onActivate(event) {
        let scrollToTop = window.setInterval(() => {
            let pos = window.pageYOffset;
            if (pos > 0) {
                window.scrollTo(0, pos - 20); // how far to scroll on each step
            } else {
                window.clearInterval(scrollToTop);
            }
        }, 16);
    }

모든 구성 요소가 스크롤을 트리거하는 것은 아니라고 선택적으로 사용하려면 다음을 확인할 수 있습니다.

onActivate(e) {
    if (e.constructor.name)==="login"{ // for example
            window.scroll(0,0);
    }
}


Angular6.1 이후로 { scrollPositionRestoration: 'enabled' }열심히로드 된 모듈 에서도 사용할 수 있으며 모든 경로에 적용됩니다.

RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })

또한 부드러운 스크롤을 수행합니다. 그러나 이것은 모든 라우팅에서 수행하기에는 불편합니다.


다른 해결책은 라우터 애니메이션에서 상단 스크롤을 수행하는 것입니다. 맨 위로 스크롤하려는 모든 전환에 다음을 추가하십시오.

query(':enter, :leave', style({ position: 'fixed' }), { optional: true }),

4
그것의 작동. 답변 해 주셔서 감사합니다. 당신은 나를 위해 많은 시간을 절약
raihan

2
window객체 에 대한 스크롤 이벤트 가 각도 5에서 작동하지 않습니다. 이유가 무엇입니까?
Sahil Babbar

2
여기 진짜 영웅입니다. 가능한 좌절 시간을 절약했습니다. 감사합니다!
Anjana Silva

1
@AnjanaSilva, 긍정적 인 의견에 감사드립니다! 나는 :) 당신을 도울 수 있다는 것을 매우 기쁘게 생각
베가

2
lazyloaded 모듈에 대한 방법이 있습니까?
Pankaj Prakash

54

Angular 6에서이 문제가 발생 scrollPositionRestoration: 'enabled'하면 app-routing.module.ts의 RouterModule에 매개 변수 를 추가하여 해결할 수 있습니다 .

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

7
코드 사진을 게시하지 마십시오. 답변에 코드 자체를 복사하여 붙여 넣기 만하면됩니다.
mypetlion

2
확실한. 다음에 할게요. 나는 여기에 좀 새롭다. :)
Nimezzz

4
Angular 8을 사용하는 2019 년 11 월 6 일부터 scrollPositionRestoration속성은 동적 페이지 콘텐츠 (즉, 페이지 콘텐츠가 비동기 적으로로드되는 위치)에서 작동하지 않습니다. Angular 버그 보고서 참조 : github.com/angular/angular / issues / 24547
dbeachy1

25

편집 : Angular 6+의 경우 Nimesh Nishara Indimagedara의 답변을 사용하십시오.

RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'
});

원래 답변 :

모두 실패하면 템플릿 (또는 상위 템플릿)에서 id = "top"을 사용하여 상단 (또는 원하는 위치로 스크롤)에 빈 HTML 요소 (예 : div)를 만듭니다.

<div id="top"></div>

그리고 구성 요소 :

  ngAfterViewInit() {
    // Hack: Scrolls to top of Page after page view initialized
    let top = document.getElementById('top');
    if (top !== null) {
      top.scrollIntoView();
      top = null;
    }
  }

2
이 솔루션은 저에게 효과적이었습니다 (Chrome 및 Edge에서 테스트). 허용 된 솔루션이 내 프로젝트 (Angular5)에서 작동하지 않았습니다
Rob van

@RobvanMeeuwen, 내 대답이 작동하지 않으면 아마도 동일한 방식으로 구현하지 않았을 것입니다. 이 솔루션은 directely 올바른 중 안전하지 않습니다 DOM을 조작한다
베가

@Vega, 그래서 해킹이라고 불렀습니다. 귀하의 솔루션은 적절한 것입니다. 여기 일부 사람들은 당신의 것을 구현할 수 없었기 때문에 대체 해킹을 제안했습니다. 현재 사용중인 버전에 따라 코드를 리팩토링해야합니다.
GeoRover

이 모든 솔루션이 나를 위해 일합니다. 감사 @GeoRover
Gangani의 Roshan

Angular 6+의 경우 Nimesh Nishara Indimagedara의 답변을 사용하십시오.
GeoRover


6

@Vega가 귀하의 질문에 대한 직접적인 답변을 제공하지만 문제가 있습니다. 브라우저의 뒤로 / 앞으로 버튼이 깨집니다. 사용자가 브라우저 뒤로 또는 앞으로 버튼을 클릭하면 위치를 잃고 상단으로 스크롤됩니다. 사용자가 링크로 이동하기 위해 아래로 스크롤해야하고 스크롤바가 맨 위로 재설정 된 것을 찾기 위해 뒤로 만 클릭하기로 결정한 경우 사용자에게 약간의 고통이 될 수 있습니다.

여기 문제에 대한 해결책이 있습니다.

export class AppComponent implements OnInit {
  isPopState = false;

  constructor(private router: Router, private locStrat: LocationStrategy) { }

  ngOnInit(): void {
    this.locStrat.onPopState(() => {
      this.isPopState = true;
    });

    this.router.events.subscribe(event => {
      // Scroll to top if accessing a page, not via browser history stack
      if (event instanceof NavigationEnd && !this.isPopState) {
        window.scrollTo(0, 0);
        this.isPopState = false;
      }

      // Ensures that isPopState is reset
      if (event instanceof NavigationEnd) {
        this.isPopState = false;
      }
    });
  }
}

2
고급 코드와 멋진 솔루션에 감사드립니다. 그러나 때로는 @Vega 솔루션이 더 낫습니다. 애니메이션 및 동적 페이지 높이와 관련된 많은 문제를 해결하기 때문입니다. 콘텐츠가있는 긴 페이지와 간단한 라우팅 애니메이션이있는 경우 솔루션이 좋습니다. 애니메이션과 다이나믹 블록이 많은 페이지에서 시도 해봤는데별로 좋지 않아요. 때때로 우리는 앱을 위해 '백 포지션'을 희생 할 수 있다고 생각합니다. 그러나 그렇지 않다면-당신의 솔루션은 내가 Angular에 대해 보는 것 중 최고입니다. 다시 한번 감사드립니다
데니스 Savenko에게

5

제 경우에는 방금 추가했습니다.

window.scroll(0,0);

에서 ngOnInit()잘 작동합니다.


4

Angular 버전 6 이상부터 window.scroll (0,0)을 사용할 필요가 없습니다.

6+@의 Angular 버전의 경우 라우터를 구성하는 옵션을 나타냅니다.docs

interface ExtraOptions {
  enableTracing?: boolean
  useHash?: boolean
  initialNavigation?: InitialNavigation
  errorHandler?: ErrorHandler
  preloadingStrategy?: any
  onSameUrlNavigation?: 'reload' | 'ignore'
  scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
  anchorScrolling?: 'disabled' | 'enabled'
  scrollOffset?: [number, number] | (() => [number, number])
  paramsInheritanceStrategy?: 'emptyOnly' | 'always'
  malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
  urlUpdateStrategy?: 'deferred' | 'eager'
  relativeLinkResolution?: 'legacy' | 'corrected'
}

하나는 사용할 수 scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'있는

예:

RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'|'top' 
});

스크롤링을 수동으로 제어해야하는 경우 window.scroll(0,0) Angular V6 공용 패키지에서 대신 사용할 필요가 없습니다 ViewPortScoller.

abstract class ViewportScroller {
  static ngInjectableDef: defineInjectable({ providedIn: 'root', factory: () => new BrowserViewportScroller(inject(DOCUMENT), window) })
  abstract setOffset(offset: [number, number] | (() => [number, number])): void
  abstract getScrollPosition(): [number, number]
  abstract scrollToPosition(position: [number, number]): void
  abstract scrollToAnchor(anchor: string): void
  abstract setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void
}

사용법은 매우 간단합니다. 예 :

import { Router } from '@angular/router';
import {  ViewportScroller } from '@angular/common'; //import
export class RouteService {

  private applicationInitialRoutes: Routes;
  constructor(
    private router: Router;
    private viewPortScroller: ViewportScroller//inject
  )
  {
   this.router.events.pipe(
            filter(event => event instanceof NavigationEnd))
            .subscribe(() => this.viewPortScroller.scrollToPosition([0, 0]));
}

4

mat-sidenav를 사용하는 경우 라우터 콘센트에 ID를 제공하고 (부모 및 하위 라우터 콘센트가있는 경우) 활성화 기능을 <router-outlet id="main-content" (activate)="onActivate($event)"> 사용하고이 'mat-sidenav-content'쿼리 선택기를 사용하여 맨 위로 스크롤 onActivate(event) { document.querySelector("mat-sidenav-content").scrollTo(0, 0); }


id ( router-outlet내 앱에 싱글 이 있습니다) 를 사용하지 않고도 훌륭하게 작동 합니다. 나는 또한 더 '각진 방식'으로 그것을했다 : @ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer; onActivate() { this.sidenavContainer.scrollable.scrollTo({ left: 0, top: 0 }); }
GCSDC

3

AngularJS에있는 것처럼이 문제에 대한 기본 제공 솔루션을 계속 찾고 있습니다. 하지만 그때까지는이 솔루션이 저에게 효과적입니다. 간단하고 뒤로 버튼 기능을 유지합니다.

app.component.html

<router-outlet (deactivate)="onDeactivate()"></router-outlet>

app.component.ts

onDeactivate() {
  document.body.scrollTop = 0;
  // Alternatively, you can scroll to top by using this other call:
  // window.scrollTo(0, 0)
}

zurfyx 원본 게시물의 답변


3

화면 스크롤을 조정하는 기능을 생성하기 만하면됩니다.

예를 들면

window.scroll(0,0) OR window.scrollTo() by passing appropriate parameter.

window.scrollTo (xpos, ypos)-> 예상 매개 변수.


2

다음은 각 구성 요소를 처음 방문하는 경우에만 구성 요소의 맨 위로 스크롤하는 솔루션입니다 (구성 요소마다 다른 작업을 수행해야하는 경우).

각 구성 요소에서 :

export class MyComponent implements OnInit {

firstLoad: boolean = true;

...

ngOnInit() {

  if(this.firstLoad) {
    window.scroll(0,0);
    this.firstLoad = false;
  }
  ...
}

2

export class AppComponent {
  constructor(private router: Router) {
    router.events.subscribe((val) => {
      if (val instanceof NavigationEnd) {
        window.scrollTo(0, 0);
      }
    });
  }

}


2

Angular 6.1 이상 :

당신이 사용할 수있는 솔루션에 내장 에서 사용할 수있는 6.1 이상 각도 옵션을 사용하여 scrollPositionRestoration: 'enabled'동일한을 달성하기 위해.

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

Angular 6.0 이하 :

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
import { Location, PopStateEvent } from "@angular/common";

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {

    private lastPoppedUrl: string;
    private yScrollStack: number[] = [];

    constructor(private router: Router, private location: Location) { }

    ngOnInit() {
        this.location.subscribe((ev:PopStateEvent) => {
            this.lastPoppedUrl = ev.url;
        });
        this.router.events.subscribe((ev:any) => {
            if (ev instanceof NavigationStart) {
                if (ev.url != this.lastPoppedUrl)
                    this.yScrollStack.push(window.scrollY);
            } else if (ev instanceof NavigationEnd) {
                if (ev.url == this.lastPoppedUrl) {
                    this.lastPoppedUrl = undefined;
                    window.scrollTo(0, this.yScrollStack.pop());
                } else
                    window.scrollTo(0, 0);
            }
        });
    }
}

참고 : 예상되는 동작은 페이지로 다시 이동할 때 링크를 클릭했을 때와 동일한 위치로 스크롤 된 상태로 유지되어야하지만 모든 페이지에 도달 할 때 맨 위로 스크롤되어야한다는 것입니다.



2

스크롤 기능을 찾고있는 사람은 함수를 추가하고 필요할 때마다 호출합니다.

scrollbarTop(){

  window.scroll(0,0);
}

1

이 시도:

app.component.ts

import {Component, OnInit, OnDestroy} from '@angular/core';
import {Router, NavigationEnd} from '@angular/router';
import {filter} from 'rxjs/operators';
import {Subscription} from 'rxjs';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy {
    subscription: Subscription;

    constructor(private router: Router) {
    }

    ngOnInit() {
        this.subscription = this.router.events.pipe(
            filter(event => event instanceof NavigationEnd)
        ).subscribe(() => window.scrollTo(0, 0));
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
}

1

구성 요소 : 템플릿에서 작업을 생성하는 대신 모든 라우팅 이벤트를 구독하고 NavigationEnd b / c를 스크롤합니다. 그렇지 않으면 잘못된 탐색이나 차단 된 경로 등에서이 기능이 실행됩니다. 경로를 성공적으로 탐색 한 다음 스크롤을 완화합니다. 그렇지 않으면 아무것도하지 마십시오.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {

  router$: Subscription;

  constructor(private router: Router) {}

  ngOnInit() {
    this.router$ = this.router.events.subscribe(next => this.onRouteUpdated(next));
  }

  ngOnDestroy() {
    if (this.router$ != null) {
      this.router$.unsubscribe();
    }
  }

  private onRouteUpdated(event: any): void {
    if (event instanceof NavigationEnd) {
      this.smoothScrollTop();
    }
  }

  private smoothScrollTop(): void {
    const scrollToTop = window.setInterval(() => {
      const pos: number = window.pageYOffset;
      if (pos > 0) {
          window.scrollTo(0, pos - 20); // how far to scroll on each step
      } else {
          window.clearInterval(scrollToTop);
      }
    }, 16);
  }

}

HTML

<router-outlet></router-outlet>

1

이 시도

@NgModule({
  imports: [RouterModule.forRoot(routes,{
    scrollPositionRestoration: 'top'
  })],
  exports: [RouterModule]
})

이 코드는 각도 6 <=을 지원합니다.

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