답변:
몇 가지 해결책이 있습니다. 모두 확인하십시오. :)
라우터 아울렛은 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);
}
}
{ scrollPositionRestoration: 'enabled' }
열심히로드 된 모듈 에서도 사용할 수 있으며 모든 경로에 적용됩니다.
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
또한 부드러운 스크롤을 수행합니다. 그러나 이것은 모든 라우팅에서 수행하기에는 불편합니다.
query(':enter, :leave', style({ position: 'fixed' }), { optional: true }),
window
객체 에 대한 스크롤 이벤트 가 각도 5에서 작동하지 않습니다. 이유가 무엇입니까?
Angular 6에서이 문제가 발생 scrollPositionRestoration: 'enabled'
하면 app-routing.module.ts의 RouterModule에 매개 변수 를 추가하여 해결할 수 있습니다 .
@NgModule({
imports: [RouterModule.forRoot(routes,{
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
scrollPositionRestoration
속성은 동적 페이지 콘텐츠 (즉, 페이지 콘텐츠가 비동기 적으로로드되는 위치)에서 작동하지 않습니다. Angular 버그 보고서 참조 : github.com/angular/angular / issues / 24547
편집 : 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;
}
}
@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;
}
});
}
}
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]));
}
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 }); }
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)
}
다음은 각 구성 요소를 처음 방문하는 경우에만 구성 요소의 맨 위로 스크롤하는 솔루션입니다 (구성 요소마다 다른 작업을 수행해야하는 경우).
각 구성 요소에서 :
export class MyComponent implements OnInit {
firstLoad: boolean = true;
...
ngOnInit() {
if(this.firstLoad) {
window.scroll(0,0);
this.firstLoad = false;
}
...
}
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);
}
});
}
}
참고 : 예상되는 동작은 페이지로 다시 이동할 때 링크를 클릭했을 때와 동일한 위치로 스크롤 된 상태로 유지되어야하지만 모든 페이지에 도달 할 때 맨 위로 스크롤되어야한다는 것입니다.
이 시도:
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();
}
}
구성 요소 : 템플릿에서 작업을 생성하는 대신 모든 라우팅 이벤트를 구독하고 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>