Angular 5 Cuộn lên đầu mỗi lần nhấp vào Tuyến đường


99

Tôi đang sử dụng angle 5. Tôi có một bảng điều khiển trong đó tôi có một số phần có nội dung nhỏ và một số phần có nội dung lớn đến mức tôi đang gặp phải sự cố khi thay đổi bộ định tuyến trong khi lên trên cùng. Mỗi khi tôi cần cuộn để lên đầu trang. Bất cứ ai có thể giúp tôi giải quyết vấn đề này để khi tôi thay đổi bộ định tuyến, chế độ xem của tôi luôn ở trên cùng.

Cảm ơn trước.


Câu trả lời:


210

Có một số giải pháp, hãy đảm bảo kiểm tra tất cả :)

Đầu ra bộ định tuyến sẽ phát ra activatesự kiện bất kỳ khi nào một thành phần mới đang được khởi tạo, vì vậy chúng tôi có thể sử dụng (activate)để cuộn (ví dụ) lên đầu:

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

hoặc sử dụng câu trả lời này để cuộn mượt mà

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

Nếu bạn muốn chọn lọc, nói rằng không phải mọi thành phần đều nên kích hoạt cuộn, bạn có thể kiểm tra nó:

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


Kể từ Angular6.1, chúng tôi cũng có thể sử dụng { scrollPositionRestoration: 'enabled' }trên các mô-đun được tải nhanh và nó sẽ được áp dụng cho tất cả các tuyến:

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

Nó cũng sẽ thực hiện thao tác cuộn mượt mà. Tuy nhiên, điều này có sự bất tiện khi thực hiện nó trên mọi định tuyến.


Một giải pháp khác là thực hiện thao tác cuộn trên cùng trên hoạt ảnh của bộ định tuyến. Thêm điều này vào mọi chuyển đổi mà bạn muốn cuộn lên đầu:

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

4
nó đang hoạt động. Cảm ơn câu trả lời của bạn. giúp bạn tiết kiệm rất nhiều thời gian cho tôi
raihan

2
Các sự kiện cuộn trên windowđối tượng không hoạt động trong góc 5. Bạn có đoán tại sao không?
Sahil Babbar

2
Một anh hùng thực sự ở đây. Tiết kiệm hàng giờ thất vọng có thể có. Cảm ơn bạn!
Anjana Silva

1
@AnjanaSilva, cảm ơn bạn đã nhận xét tích cực! Tôi rất vui mừng rằng nó có thể giúp bạn :)
Vega

2
Có cách nào cho mô-đun được tải xuống không?
Pankaj Prakash

53

Nếu bạn gặp sự cố này trong Angular 6, bạn có thể khắc phục nó bằng cách thêm tham số scrollPositionRestoration: 'enabled'vào RouterModule của app-routing.module.ts:

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

7
Vui lòng không đăng hình ảnh của mã. Chỉ cần sao chép và dán chính mã vào câu trả lời của bạn.
mypetlion

2
Chắc chắn rồi. Lần tới tôi sẽ. Tôi chỉ là người mới đến đây. :)
Nimezzz

4
Lưu ý rằng kể từ ngày 6 tháng 11 năm 2019 sử dụng Angular 8, ít nhất, thuộc scrollPositionRestorationtính không hoạt động với nội dung trang động (tức là nơi nội dung trang được tải không đồng bộ): hãy xem báo cáo lỗi Angular này: github.com/angular/angular / problem / 24547
dbeachy1

25

CHỈNH SỬA: Đối với Angular 6+, vui lòng sử dụng câu trả lời của Nimesh Nishara Indimagedara đề cập:

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

Câu trả lời gốc:

Nếu tất cả đều không thành công, hãy tạo một số phần tử HTML trống (ví dụ: div) ở trên cùng (hoặc cuộn đến vị trí mong muốn) với id = "top" trên mẫu (hoặc mẫu mẹ):

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

Và trong thành phần:

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

2
Giải pháp này phù hợp với tôi (đã thử nghiệm trên Chrome cũng như Edge). Giải pháp được chấp nhận không hoạt động cho dự án của tôi (Angular5)
Rob van Meeuwen

@RobvanMeeuwen, Nếu câu trả lời của tôi không hoạt động, có thể bạn đã không triển khai nó theo cách tương tự. Giải pháp này được thao tác directely DOM mà không phải là chính xác hoặc an toàn
Vega

@Vega, đó là lý do tôi gọi nó là hack. Giải pháp của bạn là một trong những giải pháp thích hợp. Một số người ở đây đã không thể triển khai của bạn vì vậy tôi đã đưa ra phương pháp hack dự phòng. Họ nên cấu trúc lại mã của họ dựa trên phiên bản mà họ đang sử dụng tại thời điểm này.
GeoRover

Từ tất cả giải pháp này là công việc cho tôi. Cảm ơn @GeoRover
Gangani Roshan

Đối với Angular 6+, vui lòng sử dụng câu trả lời của Nimesh Nishara Indimagedara.
GeoRover


6

Mặc dù @Vega cung cấp câu trả lời trực tiếp cho câu hỏi của bạn, nhưng có một số vấn đề. Nó phá vỡ nút quay lại / chuyển tiếp của trình duyệt. Nếu bạn là người dùng nhấp vào nút quay lại hoặc chuyển tiếp của trình duyệt, họ sẽ mất vị trí và bị cuộn ở trên cùng. Điều này có thể gây ra một chút khó khăn cho người dùng của bạn nếu họ phải cuộn xuống để truy cập một liên kết và quyết định nhấp lại chỉ để tìm thanh cuộn đã được đặt lại ở trên cùng.

Đây là giải pháp của tôi cho vấn đề.

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
Cảm ơn bạn vì mã nâng cao và giải pháp hay. Nhưng đôi khi giải pháp @Vega tốt hơn, vì nó giải quyết nhiều vấn đề với hoạt ảnh và chiều cao trang động. Giải pháp của bạn là tốt nếu bạn có một trang dài với nội dung và hoạt ảnh định tuyến đơn giản. Tôi thử nó trên trang có nhiều hoạt ảnh và khối động và nó có vẻ không tốt lắm. Tôi nghĩ rằng đôi khi chúng ta có thể hy sinh 'vị trí lùi' cho ứng dụng của mình. Nhưng nếu không - giải pháp của bạn là giải pháp tốt nhất mà tôi thấy cho Angular. Cảm ơn bạn một lần nữa
Denis Savenko

5

Trong trường hợp của tôi, tôi vừa thêm

window.scroll(0,0);

trong ngOnInit()và làm việc tốt của nó.


4

Từ phiên bản Angular 6+ Không cần sử dụng window.scroll (0,0)

Đối với phiên bản Angular 6+từ @ Đại diện các tùy chọn để cấu hình bộ định tuyến.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'
}

Người ta có thể sử dụng scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'trong

Thí dụ:

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

Và nếu ai đó yêu cầu điều khiển cuộn theo cách thủ công, Không cần sử dụng window.scroll(0,0) Thay thế từ gói phổ biến Angular V6 đã giới thiệu 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
}

Cách sử dụng khá đơn giản Ví dụ:

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

nếu bạn sử dụng mat-sidenav, hãy cung cấp một id cho cửa hàng bộ định tuyến (nếu bạn có cửa hàng bộ định tuyến cha và con) và sử dụng chức năng kích hoạt trong đó <router-outlet id="main-content" (activate)="onActivate($event)"> và sử dụng bộ chọn truy vấn 'mat-sidenav-content' này để cuộn lên trên onActivate(event) { document.querySelector("mat-sidenav-content").scrollTo(0, 0); }


Hoạt động tuyệt vời ngay cả khi không sử dụng id (Tôi có một router-outletứng dụng duy nhất trên ứng dụng của mình). Tôi cũng đã làm điều đó theo một cách 'góc cạnh hơn': @ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer; onActivate() { this.sidenavContainer.scrollable.scrollTo({ left: 0, top: 0 }); }
GCSDC

3

Tôi tiếp tục tìm kiếm một giải pháp tích hợp cho vấn đề này giống như trong AngularJS. Nhưng cho đến lúc đó giải pháp này phù hợp với tôi, Nó đơn giản và duy trì chức năng của nút quay lại.

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

Câu trả lời từ bài đăng gốc của zurfyx


3

Bạn chỉ cần tạo một chức năng có điều chỉnh việc cuộn màn hình của bạn

ví dụ

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

window.scrollTo (xpos, ypos) -> tham số mong đợi.


2

Đây là một giải pháp chỉ cuộn lên đầu Thành phần nếu lần đầu tiên truy cập cho TỪNG thành phần (trong trường hợp bạn cần làm điều gì đó khác nhau cho mỗi thành phần):

Trong mỗi Thành phần:

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 trở lên:

Bạn có thể sử dụng giải pháp tích hợp sẵn trong Angular 6.1+ với tùy chọn scrollPositionRestoration: 'enabled'để đạt được điều tương tự.

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

Angular 6.0 trở về trước:

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

Lưu ý: Hành vi được mong đợi là khi bạn điều hướng trở lại trang, nó sẽ vẫn được cuộn xuống cùng vị trí khi bạn nhấp vào liên kết, nhưng cuộn lên đầu khi đến mọi trang.



2

Đối với một số người đang tìm kiếm chức năng cuộn, chỉ cần thêm chức năng và gọi khi cần

scrollbarTop(){

  window.scroll(0,0);
}

1

Thử cái này:

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

Thành phần: Đăng ký tất cả các sự kiện định tuyến thay vì tạo một hành động trong mẫu và cuộn trên NavigationEnd b / c nếu không bạn sẽ kích hoạt tính năng này trên các điều hướng không tốt hoặc các tuyến đường bị chặn, v.v. Đây là một cách chắc chắn để biết rằng nếu một tuyến đường thành công được điều hướng đến, sau đó cuộn nhẹ nhàng. Nếu không, không làm gì 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

thử cái này

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

mã này hỗ trợ góc 6 <=

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.