在Angular 6中使用HTML锚链接片段

52

我正在使用Angular 6项目,其中我已禁用/删除了哈希位置策略,从而从URL中删除了#。

由于这个改变,链接上有:

<li routerLinkActive="active">
   <a [routerLink]="['/settings']">Contact Settings</a>
   <ul class="child-link-sub">
      <li>
         <a href="#contactTypes">Contact Types</a>
      </li>
   </ul>
</li>

不再工作,它只是跳过当前组件的URL,并在localhost后面放置#contactTypes。

我发现了这个github问题,应该可以解决这个问题。

<a [routerLink]="['/settings/']" fragment="contactTypes" >Contact Types</a>

这会将 #contactTypes 放在 URL 的末尾,但它不会滚动到浏览器的顶部。

来源:https://github.com/angular/angular/issues/6595

8个回答

62

Angular 6.1提供了一个名为anchorScrolling的选项,它位于路由器模块的ExtraOptions中。根据anchorScrolling的定义

配置是否应在url具有片段时滚动到该元素。

'disabled' -- 什么都不做(默认)。

'enabled' -- 滚动到元素。 这个选项将来将成为默认值。

在“popstate”上不会发生锚点滚动。 相反,我们恢复存储的位置或滚动到顶部。

您可以像这样使用它:

const routerOptions: ExtraOptions = {
  useHash: false,
  anchorScrolling: 'enabled',
  // ...any other options you'd like to use
};

// then just import your RouterModule with these options

RouterModule.forRoot(MY_APP_ROUTES, routerOptions)

29
谢谢您的回答。我之前没有注意到您必须使用routerLink="./" fragment="anchorName",而不能使用href="#anchorName"。 - PeterFromCologne
12
要使此功能在第二次点击时生效,您需要在routerOptions中添加 onSameUrlNavigation: 'reload'选项。 - Nitin Avula
1
请注意,此答案基于Angular 6.1,可能不适用于当前版本及以后的Angular。 - Machado
2
已确认,这在Angular 11中也有效。上面提到的所有选项也都有效,即anchorScrolling: 'enabled',onSameUrlNavigation: 'reload',scrollPositionRestoration: 'enabled' - Krishnan
1
只是想知道,如何在页面加载时使其工作?anchorScrolling不会自动工作,例如,如果我直接在新浏览器中打开http://my-ng-app.com/route#section-1,则不会将我带到“section-1”。可能应该有一种设置或手动方式来解决这个问题? - Krishnan
显示剩余4条评论

31

我在寻找一个类似的解决方案,并尝试使用ngx-scroll-to包,发现它在最新版本的 Angular 中无法正常工作,所以决定寻找其他选项并发现可以使用scrollIntoView

HTML 代码:

<button (click)="scrollToElement(target)"></button>
<div #target>Your target</div>

Ts 代码:

  scrollToElement($element): void {
    console.log($element);
    $element.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
  }

谢谢,你的回答非常好,用简短的代码易于理解。 - WasiF
你能提供动态链接吗?虽然有其他的答案,但代码并不简单。 - WasiF
4
这并不是最理想的,因为它无法为用户提供可分享给他人的链接,例如“example.org/help#installing”。 - ANeves
1
@ANeves 是的,现在“这不是理想的”,但当我回答这个问题时,achorScrolling功能还没有推出。自从Angular 6.1后发布,这个解决方案可能对那些使用旧版本Angular的人有所帮助。随着每个新版本的Angular的推出,解决方案也在不断发展,这是非常好的。 - Joel Joseph

12

这对我来说有效(我正在使用Angular 12.1.3):

在HTML模板上:

<a (click)="scrollTo('anchorId')">Scroll to another position</a>

将要滚动到的元素的ID(不包含#号符号)传递给函数。接着,在TypeScript中,使用.scrollIntoView方法使浏览器滚动到该元素的位置。
scrollTo(element: any): void {
  (document.getElementById(element) as HTMLElement).scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
}

在HTML模板中:<div id="anchorId"> - MeerArtefakt

7

出于无障碍性的考虑,我必须在文档开头添加一个链接,以便屏幕阅读器用户可以直接访问内容,并跳过页面中反复出现的部分。

由于我需要该链接保持可聚焦(最好保留href属性),而实际上它位于app-root或任何组件之外(但解决方案仍有效于组件内),为此我使用了简单的传统HTML和JavaScript:

<a href="./#content"
     onclick="event.preventDefault(); location.hash='content';"
     class="content-shortcut"
     title="Access page content directly"
     i18n-title
     aria-label="Access page content directly"
     i18n-label>Access page content directly</a>
  <style>
    .content-shortcut {
      position: absolute;
      opacity: 0;
      height: 0px;
      font-size: 1px;
    }

    .content-shortcut:focus,
    .content-shortcut:active {
      position: relative;
      opacity: 1;
      height: auto;
      font-size: 1em;
      display: block;
      color: black;
      background: white;
    }

  </style>

这也是我要做的事情,感谢您的帖子。 - Ricardo Saracino
满足WCAG要求跳过主导航的最佳解决方案。非常简单而优雅。谢谢! - user1725382

4

这是针对Angular 9的,但我相信整个社区都会受益于此。

您可以在@angular/common中使用Location来获取当前路径。

假设您有以下带有id的元素需要聚焦

<div id="bring-me-to-the-focus">

这里仅显示提取的代码块。

import { Location } from '@angular/common';

constructor(private location: Location) { }

this.location.path() + '#bring-me-to-the-focus'; 

我相信这会对某些人有所帮助 :)
干杯。

我认为这并不必要,因为路由器提供了anchorScrollingonSameUrlNavigation功能。 - giovannipds

3
正如Nitin Avula在评论中指出的那样,如果您要导航到不同的路由或在路由配置中启用了onSameUrlNavigation,那么仅使用routerLink来进行哈希锚只能起作用。

绕过这个问题的方法是,在您的*.component.ts文件中使用this.router.navigate代替routerLink,并加上fragment参数:

HTML -

<a (click)="scrollToContactTypes()">Contact Types</a>

TypeScript -

constructor(private router: Router) { }

scrollToContactTypes() {
    this.router.onSameUrlNavigation = "reload";
    this.router.navigate(["/settings"], { fragment: "contactTypes" }).finally(() => {
        this.router.onSameUrlNavigation = "ignore"; // Restore config after navigation completes
    });
}

如果你正在假装为某些原因允许 onSameUrlNavigation = "reload" ,那么这是一个有趣的答案,我不知道。 - giovannipds

2

使用ngx page scroll插件

 <a pageScroll href="#awesomePart">Take me to the awesomeness</a>
 <h2 id="awesomePart">This is where the awesome happens</h2>

2
好的回答,运行良好。例如,如果您在/home页面,您需要执行href="home#anchor"操作。+1 - PierreD
3
你不需要使用库来实现这个功能,因为这个行为已经包含在 Angular 路由器中了。 - Machado
@Machado 是的,你说得对,我们只需要在应用程序路由模块中的ExtraOptions的forRoot里添加 anchorScrolling: 'enabled' - Santosh
@Machado 是的,你说得对,我们只需要在应用程序路由模块中的ExtraOptions的forRoot中添加anchorScrolling: 'enabled' - undefined

-1

你需要使用哈希路由策略来启用哈希滚动。

你需要将第二个参数作为一个对象传递,例如RouterModule.forRoot([],{useHash:true}})。这样就可以正常工作了。


5
哈希策略将哈希视为路由,对吗? - Ayyash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接