我遇到Angular 2的问题,从一条路线更改为另一条路线不会自动滚动到新视图的顶部。我意识到Angular 1允许将autoscroll
属性添加到HTML元素中,而其他人则提出了一些简单的javascript(例如window.scroll(0, 0)
)以强制视图在加载时滚动到顶部。
但是,我不知道如何使用Angular 2完成此任务。有谁知道如何实现这一目标?
答案 0 :(得分:17)
<强>更新强>
目前没有自动方式。
另见Angular 2 typescript error when using subscribe function on new router (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中提到)
注入路由器,订阅路由更改并调用滚动到顶部:
&gt; = RC.x
router.changes.subscribe() => {
window.scrollTo(0, 0);
});
<强>β强>
router.events
.filter(e => e instanceof NavigationEnd)
.subscribe(() => {
window.scrollTo(0, 0);
});
答案 1 :(得分:13)
你能看到这里:https://angular.io/docs/ts/latest/api/router/index/Router-class.html#!#events-anchor,自Angular 2.0.0以来你必须使用“router.events.subscribe”
因此,自动scrool到所有页面顶部的一个很好的解决方案是拥有这样的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);
}
});
}
}
答案 2 :(得分:9)
较新的RC(&gt; = RC.3)似乎没有公开changes
Observable,它可能已经重命名为events或routerEvents。
他们完全“精彩”的文档似乎没有提供任何有关正在做什么的信息,所以我猜你在那里有一个小俄罗斯轮盘。或翻硬币或其他东西。
从this回答,似乎events
Observable返回有关导航状态的事件:
router.events.subscribe(event:Event => { if(event is NavigationStart) { } // NavigationEnd // NavigationCancel // NavigationError // RoutesRecognized }
答案 3 :(得分:4)
我有同样的问题。根据Gunter的回答,我发现Angular的2 RC.1新路由器不会直接暴露Observable。相反,它有一个changes
属性用于此目的。 RC.1的解决方法是:
this._router.changes.subscribe(() => {
window.scrollTo(0, 0);
});
答案 4 :(得分:4)
我在每个页面的ngOnInit中使用if(this.router.navigated)来确定是否使用window.scrollTo(0,0)。这将覆盖大多数路由到页面的情况,同时如果单击浏览器的“后退”按钮,则将滚动位置保留在应有的位置。
if(this.router.navigated) {
window.scrollTo(0, 0);
}
答案 5 :(得分:3)
我测试的100%溶液:
constructor(router:Router){
this.router.events.subscribe(() => {
window.scrollTo(0, 0);
});
}
答案 6 :(得分:2)
我在issue thread发布了此内容,但我会在此处再次发布。
我的团队一直在angular.io上使用what the angular team uses on this repo。只需提供服务并像往常一样注入它。然后,在你想要这个行为的每个页面上的ngAfterViewInit上,只需调用它。[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(/^#/, '');
}
}
答案 7 :(得分:1)
对于那些发现window.scrollTo(0,0)
没有工作的人(我猜是因为材料设计方面而非完全猜测),请使用此处找到的方法:
Javascript / CSS window.scrollTo(0,0) not working
答案 8 :(得分:1)
我使用的是材料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 :(得分:1)
我没有在每个组件中编写代码,而是在一个地方添加了以下代码 -
<router-outlet (activate)="onActivate($event)"></router-outlet>
onActivate(e) {
window.scrollTo(0, 0);
}