Autoscroll en Angular 2
Estoy experimentando un problema con Angular 2 donde cambiar de una ruta a otra no se desplaza automáticamente a la parte superior de la nueva vista. Me doy cuenta de que Angular 1 permitió que se agregara una propiedad autoscroll
a un elemento HTML, y otros habían creado un javascript simple (como window.scroll(0, 0)
) para forzar a las vistas a desplazarse hacia la parte superior cuando se cargaban.
Sin embargo, no estoy seguro de cómo lograr esto con Angular 2. ¿Alguien sabe cómo lograrlo?
10 answers
Update
Actualmente no hay forma automática.
Ver también Error Angular 2 typescript al usar la función subscribe en un nuevo router (rc 1)
Véase también 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
En el nuevo router V3-beta.2 puede pasar un fragmento con enlaces de enrutador y navegación de enrutador
<a [routerLink]="..." fragment="top">
Debe desplazarse hasta él, pero también agrega #top
a la URL (no probado yo mismo todavía)
Update
Original
Hay un tema abierto que cubre esto https://github.com/angular/angular/issues/6595
Una solución alternativa (mencionada en https://github.com/angular/angular/issues/6946 )
Inyecte el enrutador, suscríbase a los cambios de ruta e invoque el desplazamiento hacia arriba:
>= RC.x
router.changes.subscribe() => {
window.scrollTo(0, 0);
});
Beta
router.events
.filter(e => e instanceof NavigationEnd)
.subscribe(() => {
window.scrollTo(0, 0);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:20
Tiene que ver aquí: https://angular.io/docs/ts/latest/api/router/index/Router-class.html#! # events-anchor , tienes que usar "router.evento.suscribirse " desde Angular 2.0.0
Así que una buena solución para automáticamente scrool a la parte superior de toda la página es tener un AppComponent como este:
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);
}
});
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-22 12:51:31
Nuevos RCs (>= RC.3) no parece exponer un changes
Observable, probablemente desde entonces ha sido renombrado a events o routerEvents.
Sus documentos absolutamente "fantásticos" no parecen proporcionar ninguna información sobre lo que está haciendo qué, así que supongo que te espera un poco de Ruleta rusa allí. O lanzar una moneda o algo.
De esta respuesta , parece que el events
Observable devuelve eventos con respecto al estado de navegación:
router.events.subscribe(event:Event => { if(event is NavigationStart) { } // NavigationEnd // NavigationCancel // NavigationError // RoutesRecognized }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:20
Tuve el mismo problema. Basándome en la respuesta de Gunter, encontré el 2 RC de Angular.1 el nuevo router no expone un Observable directamente. En su lugar tiene una propiedad changes
para ese propósito. La solución para RC.1 es:
this._router.changes.subscribe(() => {
window.scrollTo(0, 0);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-12 23:57:55
He usado si (esto.router.navegado) en el ngOnInit de cada página para determinar si usar o no la ventana.scrollTo (0, 0). Esto cubrirá la mayoría de los casos de enrutamiento a la página, dejando la posición de desplazamiento donde debería estar si hace clic en el botón de retroceso del navegador.
if(this.router.navigated) {
window.scrollTo(0, 0);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-21 15:16:05
Solución 100% probada por mí:
constructor(router:Router){
router.events.subscribe(() => {
window.scrollTo(0, 0);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-15 15:22:50
Publiqué esto en el hilo de discusión , pero lo publicaré de nuevo aquí.
Mi equipo ha estado usando lo que el equipo angular usa en este repositorio en angular.io. Solo haz un servicio e inyéctalo como de costumbre. Luego, en ngAfterViewInit en cada página que desee este comportamiento, simplemente llame a esto.[scroll service variable name].scrollToTop(). Finalmente, necesitarás agregar esto a la parte superior de <body>
en index.html: <div id="top-of-page"></div>
Código de servicio:
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(/^#/, '');
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-15 21:34:17
Para aquellos de ustedes que encuentran window.scrollTo(0,0)
no funciona (supongo que debido a material design sidenav pero totalmente adivinando) use el método que se encuentra aquí:
Ventana Javascript / CSS.scrollTo (0,0) no funciona
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:30
Estoy usando material sidenav y no pude obtener ninguna de las respuestas sugeridas para trabajar para mí. Aquí está mi solución de trabajo:
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;
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-30 18:52:31
En lugar de escribir código en cada componente, agregué el siguiente código en un solo lugar:
<router-outlet (activate)="onActivate($event)"></router-outlet>
onActivate(e) {
window.scrollTo(0, 0);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-20 12:44:50