web-dev-qa-db-ja.com

自動スクロールAngular 2

Angular 2で問題が発生し、あるルートから別のルートに変更しても新しいビューの上部に自動的にスクロールしません。Angular 1はautoscrollプロパティをHTML要素に追加することを許可し、他のものはロード時にビューを強制的に一番上にスクロールするためのいくつかの単純なjavascript(window.scroll(0, 0)など)を考え出しました。

ただし、Angular 2.でこれを達成する方法がわかりません。

23
Chris Ryan

update

現在、自動的な方法はありません。

新しいルーター(rc 1)でサブスクライブ機能を使用すると、Angular 2 TypeScriptエラーが発生する も参照してください。

参照してください 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); }
        }
      }
    });
  }
}

update

新しいルーター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);
});
17

あなたはここに見ることができます: https://angular.io/docs/ts/latest/api/router/index/Router-class.html#!#events-anchor 、使用する必要がありますrouter.events.subscribe "since 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);
            }
        });
    }
}
13
Thierry

新しいRC(> = RC.3)はchanges Observableを公開していないようです。それ以降はおそらく events または routerEvents に名前が変更されています。

彼らの完全に「素晴らしい」ドキュメントは、何が何をしているのかに関する情報を提供していないようです。または、コインなどをひっくり返します。

this answerから、events Observableはナビゲーション状態に関するイベントを返すようです:

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

各ページのngOnInitでif(this.router.navigated)を使用して、window.scrollTo(0、0)を使用するかどうかを決定しました。これは、ページへのルーティングのほとんどのケースをカバーしますが、ブラウザの[戻る]ボタンをクリックした場合のスクロール位置はそのままにしておきます。

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

同じ問題がありました。 Gunterの答えに基づいて、Angularの2 RC.1の新しいルーターはObservableを直接公開しないことがわかりました。代わりに、そのためのchangesプロパティがあります。 RC.1の回避策は次のとおりです。

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

これを issue thread に投稿しましたが、ここに再度投稿します。

私のチームは、angular.ioで angularチームがこのリポジトリで使用するもの を使用しています。サービスを作成し、通常のように注入します。その後、それぞれのngAfterViewInitでこの動作が必要なページは、this。[scroll service variable name] .scrollToTop()を呼び出すだけです。最後に、これをindex.htmlの<body>の先頭に追加する必要があります:<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(/^#/, '');
  }
}
2
dockleryxk

window.scrollTo(0,0)が機能しない(私はマテリアルデザインのサイドナブのために推測していますが、完全に推測している)場合は、次の方法を使用してください: Javascript/CSS window.scrollTo(0,0)動作していません

1
Helzgate

マテリアルサイドナブを使用していますが、提案された回答を得ることができませんでした。私の作業ソリューションは次のとおりです。

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;
    }
  }
}
1
Tyson

各コンポーネントにコードを記述する代わりに、次のコードを1か所に追加しました-

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

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