Подтвердить что ты не робот

Автопрокрутка в Angular 2

У меня возникла проблема с Angular 2, когда переход с одного маршрута на другой автоматически не прокручивается до вершины нового представления. Я понимаю, что Angular 1 допускал добавление свойства autoscroll к элементу HTML, а другие придумали какой-то простой javascript (например, window.scroll(0, 0)), чтобы заставить виды прокручивать вверх при загрузке.

Однако я не уверен, как это сделать с помощью Angular 2. Кто-нибудь знает, как достичь этого?

4b9b3361

Ответ 1

Обновление

В настоящее время нет автоматического способа.

См. также Angular 2 typescript ошибка при использовании функции подписки на новом маршрутизаторе (rc 1)

См. также https://github.com/angular/angular/issues/6595#issuecomment-244232725

class MyAppComponent {
  constructor(router: Router) {
    router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = router.parseUrl(router.url);
        if (tree.fragment) {
          // you can use DomAdapter
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(element); }
        }
      }
    });
  }
}

Обновление

В новом маршрутизаторе V3-beta.2 вы можете передать фрагмент с маршрутизаторными ссылками и маршрутизацией навигации

<a [routerLink]="..." fragment="top">

он должен прокручиваться до него, но также добавляет #top к URL-адресу (еще не проверял себя)

Обновление

Оригинал

Существует открытый вопрос, охватывающий этот https://github.com/angular/angular/issues/6595

Обходной путь (упомянутый в https://github.com/angular/angular/issues/6946)

Ввести маршрутизатор, подписаться на изменения маршрута и вызвать прокрутку вверх:

= RC.x

router.changes.subscribe() => {
  window.scrollTo(0, 0);
});

бета

router.events
.filter(e => e instanceof NavigationEnd)
.subscribe(() => {
  window.scrollTo(0, 0);
});

Ответ 2

Вы можете видеть здесь: https://angular.io/docs/ts/latest/api/router/index/Router-class.html#!#events-anchor, вам нужно использовать "router.events.subscribe", поскольку Angular 2.0.0

Итак, хорошим решением для автоматического поиска в верхней части страницы является наличие AppComponent следующим образом:

import {Component} from '@angular/core';
import {Router, NavigationEnd} from "@angular/router";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
    constructor(private router: Router) {
        router.events.subscribe((val) => {
            if (val instanceof NavigationEnd){
                window.scrollTo(0,0);
            }
        });
    }
}

Ответ 3

Новые RCs ( >= RC.3), похоже, не отображают a changes Observable, вероятно, с тех пор он был переименован в events или routerEvents.

Их совершенно "фантастические" документы, похоже, не дают никакой информации о том, что делать, поэтому, я думаю, вы находитесь за русскую рулетку. Или переверните монету или что-то еще.

В ответе this кажется, что events Observable возвращает события, касающиеся состояния навигации:

router.events.subscribe(event:Event => {
    if(event is NavigationStart) {
    }
    // NavigationEnd
    // NavigationCancel
    // NavigationError
    // RoutesRecognized   
  }

Ответ 4

У меня была такая же проблема. Основываясь на ответе Гюнтера, я обнаружил, что новый маршрутизатор Angular 2 RC.1 не предоставляет прямой видимости. Вместо этого он имеет свойство changes для этой цели. Обходной путь для RC.1:

this._router.changes.subscribe(() => {
    window.scrollTo(0, 0);
}); 

Ответ 5

Я использовал if (this.router.navigated) в ngOnInit каждой страницы, чтобы определить, следует ли использовать window.scrollTo(0, 0). Это будет охватывать большинство случаев маршрутизации на страницу, оставляя положение прокрутки, где оно должно быть, если вы нажмете кнопку "Назад браузера".

if(this.router.navigated) {
  window.scrollTo(0, 0);
}

Ответ 6

100% -ное решение, проверенное мной:

constructor(router:Router){
    router.events.subscribe(() => {
        window.scrollTo(0, 0);

    }

Ответ 7

Для тех из вас, кто ищет window.scrollTo(0,0) не работает (я предполагаю, что из-за материального дизайна sidenav, но полностью угадываю) используйте метод, найденный здесь: Javascript/CSS window.scrollTo(0,0) не работает

Ответ 8

Я использую материал sidenav, и я не мог получить ни один из предложенных ответов для работы для меня. Здесь мое рабочее решение:

import { Router, NavigationEnd } from '@angular/router';

...

constructor(
  private router: Router,
) {
  router.events.subscribe(event => {
    if (event instanceof NavigationEnd) {
      document.querySelector('.mat-sidenav-content').scrollTop = 0;
    }
  }
}

Ответ 9

Я разместил это в проблеме, но я отправлю его здесь еще раз.

Моя команда использует что команда angular использует в этом репо на angular.io. Просто сделайте услугу и введите ее как обычно. Затем, на ngAfterViewInit на каждой странице вы хотите это поведение, просто вызовите это. [Scroll service variable name].scrollToTop(). Наконец, вам нужно добавить это в начало <body> в index.html: <div id="top-of-page"></div>

Код службы:

import { Injectable, Inject } from '@angular/core';
import { PlatformLocation } from '@angular/common';
import { DOCUMENT } from '@angular/platform-browser';
import {fromEvent} from 'rxjs/observable/fromEvent';

export const topMargin = 16;
/**
 * A service that scrolls document elements into view
 */
@Injectable()
export class ScrollService {

  private _topOffset: number | null;
  private _topOfPageElement: Element;

  // Offset from the top of the document to bottom of any static elements
  // at the top (e.g. toolbar) + some margin
  get topOffset() {
    if (!this._topOffset) {
      const toolbar = this.document.querySelector('md-toolbar.app-toolbar');
      this._topOffset = (toolbar && toolbar.clientHeight || 0) + topMargin;
    }
    return this._topOffset;
  }

  get topOfPageElement() {
    if (!this._topOfPageElement) {
      this._topOfPageElement = this.document.getElementById('top-of-page') || this.document.body;
    }
    return this._topOfPageElement;
  }

  constructor(
      @Inject(DOCUMENT) private document: any,
      private location: PlatformLocation) {
    // On resize, the toolbar might change height, so "invalidate" the top offset.
    fromEvent(window, 'resize').subscribe(() => this._topOffset = null);
  }

  /**
   * Scroll to the element with id extracted from the current location hash fragment.
   * Scroll to top if no hash.
   * Don't scroll if hash not found.
   */
  scroll() {
    const hash = this.getCurrentHash();
    const element: HTMLElement = hash
        ? this.document.getElementById(hash)
        : this.topOfPageElement;
    this.scrollToElement(element);
  }

  /**
   * Scroll to the element.
   * Don't scroll if no element.
   */
  scrollToElement(element: Element) {
    if (element) {
      element.scrollIntoView();

      if (window && window.scrollBy) {
        // Scroll as much as necessary to align the top of `element` at `topOffset`.
        // (Usually, `.top` will be 0, except for cases where the element cannot be scrolled all the
        //  way to the top, because the viewport is larger than the height of the content after the
        //  element.)
        window.scrollBy(0, element.getBoundingClientRect().top - this.topOffset);

        // If we are very close to the top (<20px), then scroll all the way up.
        // (This can happen if `element` is at the top of the page, but has a small top-margin.)
        if (window.pageYOffset < 20) {
          window.scrollBy(0, -window.pageYOffset);
        }
      }
    }
  }

  /** Scroll to the top of the document. */
  scrollToTop() {
    this.scrollToElement(this.topOfPageElement);
  }

  /**
   * Return the hash fragment from the `PlatformLocation`, minus the leading `#`.
   */
  private getCurrentHash() {
    return this.location.hash.replace(/^#/, '');
  }
}

Ответ 10

Вместо написания кода в каждом компоненте я добавил следующий код в одном месте -

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

    onActivate(e) {
        window.scrollTo(0, 0);
    }