Angular 2で問題が発生し、あるルートから別のルートに変更しても新しいビューの上部に自動的にスクロールしません。Angular 1はautoscroll
プロパティをHTML要素に追加することを許可し、他のものはロード時にビューを強制的に一番上にスクロールするためのいくつかの単純なjavascript(window.scroll(0, 0)
など)を考え出しました。
ただし、Angular 2.でこれを達成する方法がわかりません。
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);
});
あなたはここに見ることができます: 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);
}
});
}
}
新しいRC(> = RC.3)はchanges
Observableを公開していないようです。それ以降はおそらく events または routerEvents に名前が変更されています。
彼らの完全に「素晴らしい」ドキュメントは、何が何をしているのかに関する情報を提供していないようです。または、コインなどをひっくり返します。
this answerから、events
Observableはナビゲーション状態に関するイベントを返すようです:
router.events.subscribe(event:Event => { if(event is NavigationStart) { } // NavigationEnd // NavigationCancel // NavigationError // RoutesRecognized }
各ページのngOnInitでif(this.router.navigated)を使用して、window.scrollTo(0、0)を使用するかどうかを決定しました。これは、ページへのルーティングのほとんどのケースをカバーしますが、ブラウザの[戻る]ボタンをクリックした場合のスクロール位置はそのままにしておきます。
if(this.router.navigated) {
window.scrollTo(0, 0);
}
同じ問題がありました。 Gunterの答えに基づいて、Angularの2 RC.1の新しいルーターはObservableを直接公開しないことがわかりました。代わりに、そのためのchanges
プロパティがあります。 RC.1の回避策は次のとおりです。
this._router.changes.subscribe(() => {
window.scrollTo(0, 0);
});
これを 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(/^#/, '');
}
}
window.scrollTo(0,0)
が機能しない(私はマテリアルデザインのサイドナブのために推測していますが、完全に推測している)場合は、次の方法を使用してください: Javascript/CSS window.scrollTo(0,0)動作していません
マテリアルサイドナブを使用していますが、提案された回答を得ることができませんでした。私の作業ソリューションは次のとおりです。
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か所に追加しました-
<router-outlet (activate)="onActivate($event)"></router-outlet>
onActivate(e) {
window.scrollTo(0, 0);
}