Angular 5在每次路线点击时滚动到顶部

rai*_*han 64 javascript scrolltop typescript angular angular-router

我正在使用角度5.我有一个仪表板,我有几个部分内容很少,几个部分内容如此之大,以至于我在更换路由器时遇到问题.每次我需要滚动到顶部.任何人都可以帮助我解决这个问题,以便当我更改路由器时,我的视图始终保持在顶部.

提前致谢.

Veg*_*ega 141

每当实例化新组件时,路由器插座都会发出激活事件,因此(activate)事件可能是滚动(例如)到顶部:

app.component.html

<router-outlet (activate)="onActivate($event)" ></router-outlet>
Run Code Online (Sandbox Code Playgroud)

app.component.ts

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

或使用此答案平滑滚动

    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);
    }
Run Code Online (Sandbox Code Playgroud)

如果你希望有选择性,说不是每个组件都应该触发滚动,你可以检查它:

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

  • 它的工作.感谢您的回答.你为我节省了很多时间 (3认同)
  • “ window”对象上的滚动事件在角度5中不起作用。有什么猜测吗? (2认同)
  • 一个真正的英雄。节省了无聊的时间。谢谢! (2认同)
  • 有没有办法延迟加载模块? (2认同)

Nim*_*zzz 40

如果有人在Angular 6中遇到此问题,您可以通过在app-routing.module.ts的RouterModule中添加以下参数来修复它.

在此输入图像描述

复制并粘贴:{scrollPositionRestoration:'enabled'}

  • 请不要发布代码图片.只需将代码本身复制粘贴到您的答案中即可. (7认同)
  • 请注意,截至 2019 年 11 月 6 日,使用 Angular 8 时,至少“scrollPositionRestoration”属性不适用于动态页面内容(即异步加载页面内容):请参阅此 Angular 错误报告:https:// github.com/Angular/Angular/issues/24547 (5认同)
  • 当然。下次我会的。我是这里的新手。:) (2认同)

Geo*_*ver 19

如果全部失败,则在模板(或父模板)上创建一个空的HTML元素(例如:div)(或者想要滚动到位置),其中id ="top":

RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'
});
Run Code Online (Sandbox Code Playgroud)

在组件中:

<div id="top"></div>
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案对我有用(在 Chrome 和 Edge 上测试过)。接受的解决方案不适用于我的项目(Angular5) (2认同)

Abd*_*fay 15

现在,Angular 6.1中提供了一个内置解决方案,scrollPositionRestoration可选.

请参阅Angular 2的回答滚动到Route Change的顶部.


Vik*_*kas 8

从 Angular 版本 6+ 开始不需要使用 window.scroll(0,0)

对于6+来自@ Represents 的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'
}
Run Code Online (Sandbox Code Playgroud)

人们可以使用scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'

例子:

RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'|'top' 
});
Run Code Online (Sandbox Code Playgroud)

如果需要手动控制滚动,无需使用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
}
Run Code Online (Sandbox Code Playgroud)

用法非常简单 示例:

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]));
}
Run Code Online (Sandbox Code Playgroud)

  • 奇怪的是,每个解决方案在某些情况下有效,而在其他情况下失败。角度滚动到顶部存在严重缺陷。 (2认同)
  • 使用 viewPortScroller.scrollToPosition([0, 0] 并不总是滚动到顶部。将参数更改为 [0, -50] 并且每次都有效。在我的例子中,上面有一个大约 50px 高的页面标题组件app.component.html 中的 &lt;router-outlet&gt; 理论上,scrollToPosition 相对于 &lt;router-outlet&gt; 滚动。 (2认同)

Ani*_*AOU 7

只需在文件中添加这一行app.module.ts

RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled' //scroll to the top
})
Run Code Online (Sandbox Code Playgroud)

我正在使用 Angular 11.1.4,它对我有用


Zoh*_*Ali 6

就我而言,我刚刚添加了

window.scroll(0,0);
Run Code Online (Sandbox Code Playgroud)

ngOnInit()和它的工作正常。


s s*_*rif 6

Angular 6.1 及更高版本:

您可以使用Angular 6.1+中提供的内置解决方案以及选项来实现相同的目的。scrollPositionRestoration: 'enabled'

@NgModule({
  imports: [RouterModule.forRoot(routes,{
    scrollPositionRestoration: 'enabled'
  })],
  exports: [RouterModule]
})
Run Code Online (Sandbox Code Playgroud)

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);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:预期的行为是,当您导航回页面时,它应该保持向下滚动到单击链接时的相同位置,但在到达每个页面时滚动到顶部。


Sal*_*808 5

尽管@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;
      }
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您提供高级代码和完善的解决方案。但是有时@Vega解决方案更好,因为它解决了动画和动态页面高度方面的许多问题。如果您的内容页长且路由动画简单,则解决方案很好。我在页面上尝试了许多动画和动力学块,但效果似乎不太好。我认为有时候我们可以为我们的应用牺牲“后退位置”。但是,如果没有,您的解决方案将是Angular最好的解决方案。再次感谢你 (2认同)

小智 5

如果您使用 mat-sidenav 为路由器插座提供 id(如果您有父路由器插座和子路由器插座)并在其中使用激活功能 <router-outlet id="main-content" (activate)="onActivate($event)"> 并使用此“mat-sidenav-content”查询选择器滚动顶部 onActivate(event) { document.querySelector("mat-sidenav-content").scrollTo(0, 0); }


小智 5

由于某种原因,以上内容都不适合我:/,因此我将元素引用添加到 中的顶部元素app.component.html,并(activate)=onNavigate($event)添加到router-outlet.

<!--app.component.html-->
<div #topScrollAnchor></div>
<app-navbar></app-navbar>
<router-outlet (activate)="onNavigate($event)"></router-outlet>
Run Code Online (Sandbox Code Playgroud)

然后,我将子项添加到 app.component.ts 文件中,类型为ElementRef,并在激活路由器出口时让它滚动到该文件。

export class AppComponent  {
  @ViewChild('topScrollAnchor') topScroll: ElementRef;

  onNavigate(event): any {
    this.topScroll.nativeElement.scrollIntoView({ behavior: 'smooth' });
  }
}
Run Code Online (Sandbox Code Playgroud)

这是stackblitz中的代码


Sav*_*iya 1

@ViewChild('topScroll') topScroll: ElementRef;

ngAfterViewInit()
{
      interval(1000).pipe(
      switchMap(() => of(this.topScroll)),
      filter(response => response instanceof ElementRef),
      take(1))
      .subscribe((input: ElementRef) => {
           input.nativeElement.scrollTop = 0;
       });
 }
Run Code Online (Sandbox Code Playgroud)

这对我来说就像一个魅力。如果你严格想遵循角度方式。