如何在角度 2+ 的元素上调用 scrollIntoView

Posted

技术标签:

【中文标题】如何在角度 2+ 的元素上调用 scrollIntoView【英文标题】:How to call scrollIntoView on an element in angular 2+ 【发布时间】:2018-05-16 22:38:27 【问题描述】:

我想在组件中的 html 元素上调用 scrollIntoView。

在 angular.js 1 中,我可以在控制器中执行类似的操作:

var element = $window.document.getElementById(id);
element.scrollIntoView( behavior: "smooth", block: "start" );

如何在 Angular 2+ 中做同样的事情?

【问题讨论】:

【参考方案1】:

首先在元素中添加一个模板引用变量(#myElem):

<p #myElem>Scroll to here!</p>

然后在组件中创建一个属性为ViewChild的属性,并在其上调用.nativeElement.scrollIntoView

export class MyComponent 
  @ViewChild("myElem") MyProp: ElementRef;

  ngOnInit() 
    this.MyProp.nativeElement.scrollIntoView( behavior: "smooth", block: "start" );
  

【讨论】:

关于 nativeElement 的具体建议(或反建议)是什么? 每次出现这种情况时,都是“不要使用 nativeElement”,并且没有讨论“推荐的方式”。 目前官方推荐使用Renderer2包裹nativeElement private el: ElementRef, private renderer: Renderer2 -- this.el.nativeElement.style.color = 'blue'; //不推荐 this.renderer2.setStyle(this.el.nativeElement, 'color', 'blue'); //推荐 但是我看不到scrollIntoView的renderer2支持 @Drenai 你如何定义推荐方式?其简单的 dom 操作。 Angular 确实提供了 Renderer2,但不支持滚动等某些操作。你也正在使用 document.queryselector 做同样的事情,那么推荐怎么做.. nativeElement 正在选择同样的事情【参考方案2】:

你可以拦截 NavigationEnd 事件

    private scrollToSectionHook() 
    this.router.events.subscribe(event => 
        if (event instanceof NavigationEnd) 
            const tree = this.router.parseUrl(this.router.url);
            if (tree.fragment) 
                const element = document.querySelector('#' + tree.fragment);
                if (element) 
                    setTimeout(() => 
                        element.scrollIntoView(behavior: 'smooth', block: 'start', inline: 'nearest');
                    , 500 );
                
            
         
    );

【讨论】:

这太棒了!应该是公认的答案。即插即用,只需注入路由器并导入navigationEvent!哇,谢谢。 这是一个非常好的答案! element.scrollIntoView 的 SetTimeout 确实有帮助!【参考方案3】:

您可以在 Angular 2+ 中实现相同的动画滚动到元素,只需在单击时传递元素,如下所示:

<button mat-fab (click)="scroll(target)">
    <i class="material-icons">
      arrow_drop_down
    </i>
 </button>
<div #target></div>

public scroll(element: any) 
    element.scrollIntoView( behavior: 'smooth' );
  

【讨论】:

您的解决方案对我来说不起作用,分配了element=document.querySelector('#target'); element.scrollIntoView( behavior: 'smooth', block: 'start' ); 比它起作用,:) 上述解决方案适用于点击,您需要将元素作为参数传递给方法,这就是您不需要使用“element=document.querySelector('#target ')" 我收回我的话,它有效,我传递的是元素的名称而不是元素,所以它让我使用 querySelector "start"是block的默认值,按原样添加没有意义。【参考方案4】:

我们的混合动力车遇到了一些问题,但这些都不起作用。如果您只想要一个简单的解决方案,您还可以选择添加超时以脱离 Angular。

例如

&lt;a (click)="onClick('foo')"&gt;

onClick(id: string): void 
    const el: HTMLElement|null = document.getElementById(id);
    if (el) 
      setTimeout(() =>
        el.scrollIntoView(behavior: 'smooth', block: 'start', inline: 'nearest'), 0);
    
  

【讨论】:

【参考方案5】:

它已经在不久前得到了回答,但是实现它的最简洁的方法是在指令上执行该操作,这也提供了可重用性。

这里有一个指令的例子,它会滚动一个元素到视图中,通过鼠标点击触发:

import Directive, ElementRef, HostListener from '@angular/core';

@Directive(
    selector: '[ScrollIntoViewOnClick]'
)
export class ScrollIntoViewOnClickDirective 

    constructor(private _elementRef: ElementRef) 
    

    @HostListener('click', ['$event.target'])
    scrollIntoView() 
        setTimeout(() => 
            this._elementRef.nativeElement.scrollIntoView(behavior: 'smooth');
        , 200)
    

那么您所要做的就是在相关元素上添加该指令以在单击时触发该功能。

希望它对任何人都有帮助。

【讨论】:

【参考方案6】:

scrollIntoView

有3种简单的使用方法

Link to Stackblitz

第一种方式

在 app.component.html 文件中:

<button (click)="scrollPoint1(point_1)">
  Click to scroll - Point 1
</button>

<div>
  <h3 #point_1>Point 1</h3>
</div>

在 app.component.ts 文件中:

scrollPoint1(el: HTMLElement) 
  // el.scrollIntoView(behavior: "smooth");
  el.scrollIntoView();

第二种方式

在 app.component.html 文件中:

<button click)="scrollPoint2()">
  Click to scroll - Point 2
</button>

<div>
  <h3 id="point_2">Point 2</h3>
</div>

在 app.component.ts 文件中:

scrollPoint2() 
  // document.getElementById("point_2").scrollIntoView(behavior: "smooth");
  document.getElementById('point_2').scrollIntoView();

第三条路

在 app.component.html 文件中:

<button (click)="scrollPoint3()">
  Click to scroll - Point 3
</button>

<div>
  <h3 #point_3>Point 3</h3>
</div>

在 app.component.ts 文件中:

@ViewChild('point_3') private my_point_3: ElementRef;
scrollPoint3() 
  // this.my_point_3.nativeElement.scrollIntoView(behavior: "smooth");
  this.my_point_3.nativeElement.scrollIntoView();

【讨论】:

【参考方案7】:

我正在使用 Capacitor 来包装一个 Angular 应用程序。 scrollIntoView 不起作用,但将其包装在 setTimeout() 函数中以使其成为同步调用。我不知道为什么。尝试在构造函数中打开模式/对话框时,我遇到了类似的问题。 .

【讨论】:

【参考方案8】:

我只能通过包装 requestAnimationFramesetTimeout 来让它工作

@ViewChild('someElement') someElementRef: ElementRef;

...

requestAnimationFrame(() => 
  this.someElementRef.nativeElement.scrollIntoView( behavior: 'smooth' );
);
<div #someElement>test</div>

【讨论】:

以上是关于如何在角度 2+ 的元素上调用 scrollIntoView的主要内容,如果未能解决你的问题,请参考以下文章

从技术角度来看,Selenium 如何点击网页上的元素?

如何在角度 2 中调用另一个组件方法

如何获取角度2中元素的属性值?

在快速服务器上成功调用 api 后重定向具有角度路由的页面

如何仅使用角度指令将放置元素拖放到日历中

如何使用角度指令动态地使表单元素只读?