Javascript 角2中的自动滚动

Javascript 角2中的自动滚动,javascript,angular,angular2-routing,Javascript,Angular,Angular2 Routing,我在Angular 2中遇到一个问题,从一条路线更改到另一条路线不会自动滚动到新视图的顶部。我意识到Angular 1允许将autoscroll属性添加到HTML元素,而其他人则提出了一些简单的javascript(例如window.scroll(0,0))来强制视图在加载时滚动到顶部 然而,我不知道如何用Angular 2实现这一点。有人知道如何做到这一点吗?更新 目前没有自动方式 另见 另见 更新 在新的路由器V3 beta.2中,您可以传递带有路由器链接和路由器导航的片段 <a [r

我在Angular 2中遇到一个问题,从一条路线更改到另一条路线不会自动滚动到新视图的顶部。我意识到Angular 1允许将
autoscroll
属性添加到HTML元素,而其他人则提出了一些简单的javascript(例如
window.scroll(0,0)
)来强制视图在加载时滚动到顶部


然而,我不知道如何用Angular 2实现这一点。有人知道如何做到这一点吗?

更新

目前没有自动方式

另见

另见


更新

在新的路由器V3 beta.2中,您可以传递带有路由器链接和路由器导航的片段

<a [routerLink]="..." fragment="top">
测试版

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

我也有同样的问题。根据冈特的回答,我发现Angular的2 RC.1新路由器并没有直接暴露出可观测的物体。相反,它有一个用于此目的的
changes
属性。RC.1的解决方法是:

this._router.changes.subscribe(() => {
    window.scrollTo(0, 0);
}); 
较新的RCs(>=RC.3)似乎没有公开可观察到的
更改,它可能已经被重命名为或

他们完全“神奇”的文档似乎没有提供任何关于正在做什么的信息,所以我猜你是在玩俄罗斯轮盘赌。或者扔硬币什么的

从回答中,似乎
事件
可观察返回有关导航状态的事件:


对于那些发现
window.scrollTo(0,0)
不起作用的人(我猜测是因为材质设计方面的原因,但完全是猜测),请使用以下方法:

我在每页的ngOnInit中使用if(this.router.navigated)来确定是否使用window.scrollTo(0,0)。这将涵盖大多数路由到页面的情况,同时保留滚动位置(如果单击浏览器后退按钮)

if(this.router.navigated) {
  window.scrollTo(0, 0);
}
您可以在这里看到:,从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);
            }
        });
    }
}

由我测试的100%溶液:

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

我正在使用material 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;
    }
  }
}

我没有在每个组件中编写代码,而是在一个地方添加了以下代码-

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

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

激活(e){
滚动到(0,0);
}
我在中发布了这篇文章,但我会在这里再次发布

我的团队一直在angular.io上使用。只要做一个服务,像往常一样注入它。然后,在ngAfterViewInit的每个页面上,只要调用[scroll service variable name].scrollToTop()即可。最后,您需要将其添加到index.html中的
顶部:

服务代码:

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(/^#/, '');
  }
}
从'@angular/core'导入{Injectable,injection};
从“@angular/common”导入{PlatformLocation};
从“@angular/platform browser”导入{DOCUMENT};
从'rxjs/observable/fromEvent'导入{fromEvent};
导出常数topMargin=16;
/**
*将文档元素滚动到视图中的服务
*/
@可注射()
导出类滚动服务{
private _topOffset:number | null;
private _topOfPageElement:Element;
//从文档顶部到任何静态元素底部的偏移量
//在顶部(例如工具栏)+一些边距
获取topOffset(){
如果(!this.\u topOffset){
const-toolbar=this.document.querySelector('md-toolbar.app-toolbar');
这._topOffset=(toolbar和toolbar.clientHeight | | 0)+topMargin;
}
返回此项。\u topOffset;
}
获取topOfPageElement(){
如果(!this.\u topOfPageElement){
this._topOfPageElement=this.document.getElementById('top-of-page')| | this.document.body;
}
返回此.\u topOfPageElement;
}
建造师(
@注入(文件)私人文件:任何,
专用位置:平台位置){
//调整大小时,工具栏可能会更改高度,因此“使顶部偏移无效”。
fromEvent(窗口,“调整大小”).subscribe(()=>this.\u topOffset=null);
}
/**
*滚动到id从当前位置哈希片段提取的元素。
*如果没有哈希,则滚动到顶部。
*如果未找到哈希,则不滚动。
*/
卷轴(){
const hash=this.getCurrentHash();
常量元素:HTMLElement=hash
?this.document.getElementById(散列)
:this.topOfPageElement;
此.scrollToElement(元素);
}
/**
*滚动到元素。
*如果没有元素,则不要滚动。
*/
scrollToElement(元素:元素){
if(元素){
元素。scrollIntoView();
if(window&&window.scrollBy){
//尽可能多地滚动以对齐“topOffset”处的“element”顶部。
//(通常,`.top`将为0,除非该元素不能在所有时间滚动。)
//由于视口的高度大于
//元素。)
scrollBy(0,element.getBoundingClientRect().top-this.topOffset);

//如果我们非常接近顶部(我更喜欢这个答案,因为代码实际上是编译的(其他答案缺少paren)我还将路由器作为私有成员注入,这应该是常见的做法。同意。我建议使用NavigationEnd作为scrolling@GünterZöchbauer我怎么能在RC5中做到这一点?请告诉我know@GünterZöchbauer,我认为代码可能有几个错误:NativationEnd应该是“NavigationEnd”,应该是“e=>e instanceof NavigationEnd”。猜对了!window.scrollTo()不起作用的原因是因为您不想滚动窗口。如果您使用的是,您想滚动窗口中的内容元素。请参阅Tyson的答案。确实,很优雅!
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;
    }
  }
}
<router-outlet (activate)="onActivate($event)"></router-outlet>

    onActivate(e) {
        window.scrollTo(0, 0);
    }
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(/^#/, '');
  }
}