Angular4 - 滚动到锚点

Posted

技术标签:

【中文标题】Angular4 - 滚动到锚点【英文标题】:Angular4 - Scrolling to anchor 【发布时间】:2017-11-10 11:39:22 【问题描述】:

我正在尝试对同一页面上的锚元素进行简单的滚动。基本上,该人单击“尝试”按钮,然后滚动到页面下方的区域,ID 为“登录”。现在,它正在使用基本的id="login"<a href="#login"></a>,但它正在跳转到该部分。理想情况下,我希望它在那里滚动。如果我使用 Angular4,是否有一些内置方法可以做到这一点,或者最简单的方法是什么?谢谢!

整个模板...(组件仍为空)

<div id="image-header">
    <div id="intro">
        <h1 class="text-center">Welcome to ThinkPlan</h1>
        <h3 class="text-center">Planning your way</h3>
        <a class="btn btn-outline-primary" href="#login" id="view">Try It</a> <!-- Where the user clicks to scroll -->
    </div>
</div>
<div class="container" id="info">
    <div class="row">
        <div class="col-md-12">
             <div class="space" id="login"></div> <!-- The place to scroll to -->
                <h1 class="text-center">ThinkPlan</h1>
                <form  class="form-horizontal">
                    <fieldset>
                        <legend>Login</legend>
                        <div class="form-group">
                            <label for="inputEmail" class="col-lg-2 control-label">Email</label>
                            <div class="col-lg-10">
                                <input type="text" class="form-control" id="inputEmail" placeholder="Email">
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="inputPassword" class="col-lg-2 control-label">Password</label>
                            <div class="col-lg-10">
                                <input type="password" class="form-control" id="inputPassword" placeholder="Password"> 
                            </div>
                        </div>
                        <div class="form-group" id="log-btn">
                            <div class="col-lg-10 col-lg-offset-2">
                                <button routerLink="/plan" type="submit" class="btn btn-outline-primary">Login</button>
                            </div>
                        </div>
                        <p class="lead text-center">New here? <a routerLink="signup">Sign up.</a></p>
                    </fieldset>
                </form>
        </div>
    </div>
</div>

【问题讨论】:

【参考方案1】:

对于 Angular 6+,您可以使用:

    在你的路由模块中:

     imports: [RouterModule.forRoot(routes,  anchorScrolling: 'enabled')]
    

    然后在你的组件html

     <a (click)="onClick('AnchorId')">Click me!</a>
     <a (click)="onClick('OtherAnchorId')">Click me, too!</a>
     ...
     <div id="AnchorId">...</div>
     ...
     <div id="OtherAnchorId">...</div>
    

    然后在你的组件中 ts

    import  ViewportScroller  from '@angular/common';
    
    @Component(
        selector: 'component-selector',
        templateUrl: './mycomponent.component.html'
    )
    export class MyComponent 
      constructor(private viewportScroller: ViewportScroller) 
    
      public onClick(elementId: string): void  
          this.viewportScroller.scrollToAnchor(elementId);
      
    
    

【讨论】:

不错,但您不需要导入:[RouterModule.forRoot(routes, anchorScrolling: 'enabled')] viewportScroller 不需要路由器模块作为依赖项 即使 Kim Kern 的回答是正确的,这感觉更像是“Angular 框架”。您还可以添加 css: "html scroll-behavior: smooth;" 使其更愉快。 完美,但是滚动事件呢? 这对于页面部分滚动很有用。要在新选项卡中打开 URL 并重定向到特定部分,请检查 @Sarah Dubois 答案。【参考方案2】:

我认为这是更简单的解决方案:

在您的 HTML 中:

<a [routerLink]="['/']" fragment="login"></a>

在你的打字稿中:

ngOnInit() 
 this.route.fragment.subscribe(fragment =>  this.fragment = fragment; );


ngAfterViewChecked(): void 
  try 
      if(this.fragment) 
          document.querySelector('#' + this.fragment).scrollIntoView();
      
   catch (e)  

【讨论】:

这会重定向到根路由。要在同一页面位置添加哈希,使用&lt;a routerLink="." fragment="login"&gt;&lt;/a&gt; 效果更好。 这种方法比 'npm install ng2-page-scroll' 更好。但它在没有平滑滚动的情况下工作 你可以像这样平滑滚动:scrollIntoView(behavior: "smooth") 呃,this.route 是什么?? @SarahDubois 这是一个非常棒的解决方案,对我使用 Angular 版本 8 非常有用。五颗星因为它的简单性。 @Phil this.route 是ActivatedRoute。您可能需要这些导入 import ActivatedRoute, Router, NavigationEnd from '@angular/router'; 我可以发布更多详细信息的答案。【参考方案3】:

自动滚动

从 Angular v6 开始,RouterModule 有了新的 anchorScrolling 选项。您可以在模块的导入中设置它:

imports: [
  ...,
  RouterModule.forRoot(routes, anchorScrolling: 'enabled')

这样,Angular 将自动滚动到具有给定片段 id 的元素。

⚠️ 但是,这在异步加载数据时不起作用,请参阅此Github issue。 ⚠️


手动滚动

Smooth scrolling 尚无法通过RouterModule 实现,但您可以手动完成:

1) 获取目标,例如ViewChild:

@ViewChild('pageInfo') pageInfo: ElementRef; 

2) 在nativeElement 上致电scrollIntoView

const targetElement = this.pageInfo.nativeElement
targetElement.scrollIntoView(behavior: "smooth")

【讨论】:

这是正确的。谢谢。要为其他人添加此内容,请使用 ViewChild 获取目标参考; @ViewChild('pageInfo') elemPageInfo: ElementRef; this.elemPageInfo.nativeElement.scrollIntoView(behavior: 'smooth'); @Ralphonzo 很高兴听到。 :-) 感谢您的精彩补充,我已经编辑了答案。 请详细说明选项2中的“targetElement”是什么。它是可滚动元素? @ShacharHar-Shuv targetElement 是您要滚动到的元素,以便它在浏览器的视口中可见。 链接到关于anchorScrolling的Angular文档here【参考方案4】:

现代单线解决方案:

export class Component implements AfterViewInit 

  constructor(
    private viewportScroller: ViewportScroller
  )  

  ngAfterViewInit(): void 
    this.route.fragment.pipe(
      first()
    ).subscribe(fragment => this.viewportScroller.scrollToAnchor(fragment));
  

【讨论】:

【参考方案5】:

所以,我只花了大约一个小时使用最新的 Angular 和其他解决方案进行初始导航,但无论我尝试什么,我都无法让锚滚动与导航历史记录一起使用。

换句话说,当我在浏览器中“返回”或“前进”时,URL 会更新,但我无法让 Angular 滚动到正确的位置。从记录来看,Angular 在后退/前进时似乎实际上并没有确认片段,因此没有触发滚动。

我受够了,决定订阅 URL 并在找到片段时手动滚动,代码如下:

ngOnInit() 
  this.router.events.subscribe(val => 
    if (val instanceof NavigationEnd) 
      let fragmentIdx = val.urlAfterRedirects.lastIndexOf('#');
      if (fragmentIdx >= 0 && fragmentIdx < val.urlAfterRedirects.length - 1) 
        let fragment = val.urlAfterRedirects.substring(fragmentIdx+1);
        console.log('fragment: ' + fragment);
        document.getElementById(fragment).scrollIntoView();
      
    
  )

为了清楚起见,您必须为要滚动到的目标元素指定 id

另外,我的链接如下所示:

<a routerLink="." fragment="anchor-name">Scroll To Anchor</a>

现在,我可以访问不同的锚点,并在我回溯/前进历史时查看滚动。希望它可以帮助某人!

【讨论】:

【参考方案6】:

在 Angular 4 中,使用锚点到同一页面可能会遇到一些问题。

我用这种方法解决了

ng2-page-scroll

安装

npm install ng2-page-scroll --save

在你的 app.module.ts 中导入

import Ng2PageScrollModule from 'ng2-page-scroll';

@NgModule(
    imports: [
        /* Other imports here */
        Ng2PageScrollModule
        ]
)
export class AppModule 

在你的 html 组件中测试它

<a pageScroll href="#test">Testing</a>
<div id="test">

【讨论】:

感谢您的全面回答,我试过了,但 npm 模块的对等依赖项已过时,具有最新的 Angular 版本。 它不起作用。在角度为 6 的列表中。单击后我的页面正在重新加载【参考方案7】:

AfterViewCheck() 会在每次触发ChangeDetection 时被调用,所以这是一个不好的解决方案。

使用AfterViewInit()点赞

public ngAfterViewInit(): void 
  this.subscription = this.route.fragment
    .subscribe(fragment => 
        const targetElement = this.document.querySelector('#' + fragment);
        if (fragment && targetElement) 
            targetElement.scrollIntoView();
         else 
            window.scrollTo(0, 0);
        
    );

public ngOnDestroy(): void 
    this.subscription.unsubscribe();

【讨论】:

为什么我们需要在 ngOnDestroy 中手动取消订阅?我认为 Angular 会自动执行它,因为它是一个路由订阅。【参考方案8】:

最后,在 Angular 7 中为我工作:

HTML:

<h1 id='here'>Here</h1>

组件:

  ngAfterViewInit() 
    this.route.fragment.subscribe(fragment => 
      this.fragment = fragment;
      setTimeout(() => this.scrollToAnchor(), 10);
    );
  

  scrollToAnchor(): void 
    try 
      if (this.fragment) 
        document.querySelector('#' + this.fragment).scrollIntoView();
      
     catch (e)  
  
  goToHere():void
    this.router.navigate(['/product'],  fragment: 'here' );
  

【讨论】:

【参考方案9】:

这是一个更详细的示例,可以添加到上述 Sarah Dubois 的答案中。

导入路由器模块。

import ActivatedRoute, Router, NavigationEnd from '@angular/router';

constructor(private route:ActivatedRoute, 
            private router:Router) 

  router.events.subscribe(event => 
    if (event instanceof NavigationEnd)     
      if (event.url) 
        this.route.fragment.subscribe(fragment => this.fragment = fragment);
      
    
  );



ngAfterViewChecked(): void 

  try 
    if(this.fragment != null) 
     document.querySelector("a[name="+this.fragment+"]").scrollIntoView();
    
   catch (e) 
    //console.log(e, 'error');
  


我喜欢使用 querySelector,它会给你很多选项来选择你想要滚动到的元素。 https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector

这适用于 Angular 8 :)

【讨论】:

以上是关于Angular4 - 滚动到锚点的主要内容,如果未能解决你的问题,请参考以下文章

如何检测自动滚动到锚点?

无法滚动到锚点

javascript 平滑滚动到锚点

javascript 滚动到锚点

javascript 平滑滚动到锚点

jQuery滚动到锚点