带有 # 标签的 Angular2路由到页面锚

我希望添加一些链接在我的 Angular2页面,当点击,将跳转到具体位置 内心该页面,像正常的标签做。所以链接应该是这样的

/users/123#userInfo
/users/123#userPhoto
/users/123#userLikes

等等。

我不认为我需要 HashLocationStrategy,因为我对标准的 Angular2方法很满意,但如果我直接添加,链接实际上会跳到根目录,而不是在同一个页面的某个地方。任何方向都可以,谢谢。

147366 次浏览

更新

现在支持这一点

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

将下面的代码添加到组件中以滚动

  import {ActivatedRoute} from '@angular/router'; // <-- do not forget to import


private fragment: string;


constructor(private route: ActivatedRoute) { }


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


ngAfterViewInit(): void {
try {
document.querySelector('#' + this.fragment).scrollIntoView();
} catch (e) { }
}

原创的

这是一个已知的问题,并在 https://github.com/angular/angular/issues/6595跟踪

虽然 君特的回答是正确的,它没有包括“跳到”锚标签的部分

因此,除此之外:

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

... 在需要“跳转到”行为的组件(父组件)中,添加:

import { Router, NavigationEnd } from '@angular/router';


class MyAppComponent {
constructor(router: Router) {


router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
const tree = router.parseUrl(router.url);
if (tree.fragment) {
const element = document.querySelector("#" + tree.fragment);
if (element) { element.scrollIntoView(true); }
}
}
});


}
}

请注意,这是一个解决方案 ! 请按照 这个 Github 问题进行更新!

A little late but here's an answer I found that works:

<a [routerLink]="['/path']" fragment="test" (click)="onAnchorClick()">Anchor</a>

在组成部分:

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


onAnchorClick ( ) {
this.route.fragment.subscribe ( f => {
const element = document.querySelector ( "#" + f )
if ( element ) element.scrollIntoView ( element )
});
}

如果你已经在一个带锚的页面上着陆,上面的代码不会自动滚动到视图,所以我在我的 ngInit 中使用了上面的解决方案,这样它也可以工作:

ngOnInit() {
this.router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
const tree = this.router.parseUrl(this.router.url);
if (tree.fragment) {
const element = document.querySelector("#" + tree.fragment);
if (element) { element.scrollIntoView(element); }
}
}
});
}

确保在组件的开始部分导入 Router、 ActivatedRoute 和 NavigationEnd,应该就可以了。

来源

上面的解决方案对我不起作用... ... 这个解决了:

首先,为 NgAfterViewChecked ()中的自动滚动准备 MyAppComponent..。

import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';


@Component( {
[...]
} )
export class MyAppComponent implements OnInit, AfterViewChecked {


private scrollExecuted: boolean = false;


constructor( private activatedRoute: ActivatedRoute ) {}


ngAfterViewChecked() {


if ( !this.scrollExecuted ) {
let routeFragmentSubscription: Subscription;


// Automatic scroll
routeFragmentSubscription =
this.activatedRoute.fragment
.subscribe( fragment => {
if ( fragment ) {
let element = document.getElementById( fragment );
if ( element ) {
element.scrollIntoView();


this.scrollExecuted = true;


// Free resources
setTimeout(
() => {
console.log( 'routeFragmentSubscription unsubscribe' );
routeFragmentSubscription.unsubscribe();
}, 1000 );


}
}
} );
}


}


}

然后,导航到发送 prodID标签的 my-app-route

import { Component } from '@angular/core';
import { Router } from '@angular/router';


@Component( {
[...]
} )
export class MyOtherComponent {


constructor( private router: Router ) {}


gotoHashtag( prodID: string ) {
this.router.navigate( [ '/my-app-route' ], { fragment: prodID } );
}


}

下面是另一个与 JavierFuentes 回答相关的变通方法:

<a [routerLink]="['self-route', id]" fragment="some-element" (click)="gotoHashtag('some-element')">Jump to Element</a>

剧本:

import {ActivatedRoute} from "@angular/router";
import {Subscription} from "rxjs/Subscription";


export class Links {
private scrollExecuted: boolean = false;


constructor(private route: ActivatedRoute) {}


ngAfterViewChecked() {
if (!this.scrollExecuted) {
let routeFragmentSubscription: Subscription;
routeFragmentSubscription = this.route.fragment.subscribe(fragment => {
if (fragment) {
let element = document.getElementById(fragment);
if (element) {
element.scrollIntoView();
this.scrollExecuted = true;
// Free resources
setTimeout(
() => {
console.log('routeFragmentSubscription unsubscribe');
routeFragmentSubscription.unsubscribe();
}, 0);
}
}
});
}
}


gotoHashtag(fragment: string) {
const element = document.querySelector("#" + fragment);
if (element) element.scrollIntoView(element);
}
}

这允许用户直接滚动到元素,如果用户直接降落在网页上有标签在 url。

但是在这种情况下,我已经在 ngAfterViewChecked中订阅了路由片段,但是每个 ngDoCheck都会连续调用 ngAfterViewChecked(),而且它不允许用户滚动回到顶部,所以在视图滚动到元素之后,在0毫秒的超时后调用 routeFragmentSubscription.unsubscribe

此外,定义了 gotoHashtag方法,以便在用户专门单击锚标记时滚动到元素。

更新:

如果 url 有查询字符串,锚中的 [routerLink]="['self-route', id]"不会保留查询字符串:

<a (click)="gotoHashtag('some-element')">Jump to Element</a>


constructor( private route: ActivatedRoute,
private _router:Router) {
}
...
...


gotoHashtag(fragment: string) {
let url = '';
let urlWithSegments = this._router.url.split('#');


if(urlWithSegments.length){
url = urlWithSegments[0];
}


window.location.hash = fragment;
const element = document.querySelector("#" + fragment);
if (element) element.scrollIntoView(element);
}

由于片段属性仍然不提供锚滚动,这个变通方法为我解决了这个问题:

<div [routerLink]="['somepath']" fragment="Test">
<a href="#Test">Jump to 'Test' anchor </a>
</div>

添加到 Kalyoyan 的 回答,这个订阅是绑定到路由器,将生活,直到页面完全刷新。在组件中订阅路由器事件时,请确保在 ngOnDestroy 中取消订阅:

import { OnDestroy } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Subscription } from "rxjs/Rx";


class MyAppComponent implements OnDestroy {


private subscription: Subscription;


constructor(router: Router) {
this.subscription = router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
const tree = router.parseUrl(router.url);
if (tree.fragment) {
const element = document.querySelector("#" + tree.fragment);
if (element) { element.scrollIntoView(element); }
}
}
});
}


public ngOnDestroy() {
this.subscription.unsubscribe();
}
}

我刚刚在我自己的网站上得到了这个工作,所以我认为这将是值得张贴我的解决方案在这里。

<a [routerLink]="baseUrlGoesHere" fragment="nameOfYourAnchorGoesHere">Link Text!</a>


<a name="nameOfYourAnchorGoesHere"></a>
<div>They're trying to anchor to me!</div>

然后在组件中,确保包含以下内容:

 import { ActivatedRoute } from '@angular/router';


constructor(private route: ActivatedRoute) {
this.route.fragment.subscribe ( f => {
const element = document.querySelector ( "#" + f )
if ( element ) element.scrollIntoView ( element )
});
}

在阅读了所有的解决方案后,我寻找了一个组件,我发现了一个完全符合原始问题要求的组件: 滚动到锚链接。https://www.npmjs.com/package/ng2-scroll-to

当您安装它时,您使用的语法如下:

// app.awesome.component.ts
@Component({
...
template: `...
<a scrollTo href="#main-section">Scroll to main section</a>
<button scrollTo scrollTargetSelector="#test-section">Scroll to test section</a>
<button scrollTo scrollableElementSelector="#container" scrollYTarget="0">Go top</a>
<!-- Further content here -->
<div id="container">
<section id="main-section">Bla bla bla</section>
<section id="test-section">Bla bla bla</section>
<div>
...`,
})
export class AwesomeComponent {
}

对我来说效果很好。

以前的答案对我来说都不管用。在最后的努力中,我试着用我的模板:

<a (click)="onClick()">From Here</a>
<div id='foobar'>To Here</div>

用这个在我的:

onClick(){
let x = document.querySelector("#foobar");
if (x){
x.scrollIntoView();
}
}

对于内部链接,它的工作方式和预期的一样。这实际上并不使用锚标记,因此根本不会触及 URL。

一个不需要任何查询参数的简单解决方案是浏览器反向/转发、路由器和深度链接兼容。

<a (click)="jumpToId('anchor1')">Go To Anchor 1</a>




ngOnInit() {


// If your page is dynamic
this.yourService.getWhatever()
.then(
data => {
this.componentData = data;
setTimeout(() => this.jumpToId( window.location.hash.substr(1) ), 100);
}
);


// If your page is static
// this.jumpToId( window.location.hash.substr(1) )
}


jumpToId( fragment ) {


// Use the browser to navigate
window.location.hash = fragment;


// But also scroll when routing / deep-linking to dynamic page
// or re-clicking same anchor
if (fragment) {
const element = document.querySelector('#' + fragment);
if (element) element.scrollIntoView();
}
}

超时只是允许页面加载由 * ngIf“保护”的任何动态数据。这也可以用来滚动到页面的顶部时,改变路线-只是提供一个默认的顶部锚标记。

我刚刚测试了 nmp-滚动到中非常有用的插件,它非常适合我。然而,它的设计角4 + ,但也许有人会发现这个答案有帮助。

我尝试了这些解决方案中的大部分,但是遇到了离开和返回另一个片段的问题,它不会工作,所以我做了一些不同的工作100% ,并摆脱了在 URL 中丑陋的散列。

这是一种比我迄今为止所见到的更好的方法。

import { Component, OnInit, AfterViewChecked, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';


@Component({
selector: 'app-hero',
templateUrl: './hero.component.html',
styleUrls: ['./hero.component.scss']
})
export class HeroComponent implements OnInit, AfterViewChecked, OnDestroy {
private fragment: string;
fragSub: Subscription;


constructor(private route: ActivatedRoute) { }


ngOnInit() {
this.fragSub = this.route.fragment.subscribe( fragment => { this.fragment = fragment; })
}


ngAfterViewChecked(): void {
try {
document.querySelector('#' + this.fragment).scrollIntoView({behavior: 'smooth'});
window.location.hash = "";
} catch (e) { }
}


ngOnDestroy() {
this.fragSub.unsubscribe();
}
}

我也有同样的问题。 解决方案: 使用视图端口 scroll < a href = “ https://angular.io/api/common/Viewportscroll # scrolltoAnchor”rel = “ nofollow norefrer”> https://angular.io/api/common/viewportscroller#scrolltoanchor

--应用程序路由. 模块.ts 代码:

import { PageComponent } from './page/page.component';


const routes: Routes = [
path: 'page', component: PageComponent },
path: 'page/:id', component: PageComponent }
];


—— HTML 组件

  <a (click) = "scrollTo('typeExec')">
<mat-icon>lens</mat-icon>
</a>

——组件代码:

    import { Component } from '@angular/core';
import { ViewportScroller } from '@angular/common';




export class ParametrageComponent {


constructor(private viewScroller: ViewportScroller) {}


scrollTo(tag : string)
{
this.viewScroller.scrollToAnchor(tag);
}


}

所有其他的答案将工作的角度版本 < 6.1。但是,如果你有最新的版本,那么你就不需要做这些丑陋的黑客,因为 Angular 已经解决了这个问题。

这是问题的链接

您所需要做的就是使用 RouterModule.forRoot方法的第二个参数选项来设置 scrollOffset

@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
scrollOffset: [0, 64] // [x, y]
})
],
exports: [RouterModule]
})
export class AppRoutingModule {}

这个为我工作! ! 这个 ngFor 所以它动态锚标记,你需要等待他们渲染

HTML:

<div #ngForComments *ngFor="let cm of Comments">
<a id="Comment_\{\{cm.id}}" fragment="Comment_\{\{cm.id}}" (click)="jumpToId()">\{\{cm.namae}} Reply</a> Blah Blah
</div>

我的档案:

private fragment: string;
@ViewChildren('ngForComments') AnchorComments: QueryList<any>;


ngOnInit() {
this.route.fragment.subscribe(fragment => { this.fragment = fragment;
});
}
ngAfterViewInit() {
this.AnchorComments.changes.subscribe(t => {
this.ngForRendred();
})
}


ngForRendred() {
this.jumpToId()
}


jumpToId() {
let x = document.querySelector("#" + this.fragment);
console.log(x)
if (x){
x.scrollIntoView();
}
}

不要忘记导入 ViewChildrenQueryList等等,并添加一些构造函数 ActivatedRoute! !

与其他答案不同的是,我还将 focus()scrollIntoView()一起添加。 另外,我使用 setTimeout,因为它跳转到顶部,否则当改变 URL。不知道是什么原因,但似乎 setTimeout做了变通。

产地:

<a [routerLink] fragment="some-id" (click)="scrollIntoView('some-id')">Jump</a>

目的地:

<a id="some-id" tabindex="-1"></a>

打印稿:

scrollIntoView(anchorHash) {
setTimeout(() => {
const anchor = document.getElementById(anchorHash);
if (anchor) {
anchor.focus();
anchor.scrollIntoView();
}
});
}

很抱歉回答的有点晚; 有一个预先定义的功能在角路由文档,这有助于我们在路由与标签页锚,即 锚滚动: “启用”

步骤1:- First Import the 路由器模组 in the app.module.ts file:-

imports:[
BrowserModule,
FormsModule,
RouterModule.forRoot(routes,{
anchorScrolling: 'enabled'
})
],

步骤2:- 转到 HTML 页面,创建导航并添加两个重要属性,如 [路由器连接]碎片,用于匹配各自的 Div 的身份证:-

<ul>
<li> <a [routerLink] = "['/']"  fragment="home"> Home </a></li>
<li> <a [routerLink] = "['/']"  fragment="about"> About Us </a></li>
<li> <a [routerLink] = "['/']"  fragment="contact"> Contact Us </a></li>
</ul>

步骤3:- 通过将 身份证号码碎片:-匹配来创建 section/div

<section id="home" class="home-section">
<h2>  HOME SECTION </h2>
</section>


<section id="about" class="about-section">
<h2>  ABOUT US SECTION </h2>
</section>


<section id="contact" class="contact-section">
<h2>  CONTACT US SECTION </h2>
</section>

作为参考,我已经添加了下面的例子,通过创建一个小演示,有助于解决您的问题。

演示: < a href = “ https://routing-hashtag-page-anchors.stackblitz.io/”rel = “ noReferrer”> https://routing-hashtag-page-anchors.stackblitz.io/

使用 app-routing.module.ts中的路由器模块:

@NgModule({
imports: [RouterModule.forRoot(routes, {
useHash: true,
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
scrollOffset: [0, 64]
})],
exports: [RouterModule]
})

这会出现在你的 HTML 中:

<a href="#/users/123#userInfo">

如果这些元素 id 被添加到 url 中并不重要,你应该考虑看看这个链接:

角度2-锚链接到当前页面上的元素

// html
// add (click) event on element
<a (click)="scroll(\{\{any-element-id}})">Scroll</a>


// in ts file, do this
scroll(sectionId) {
let element = document.getElementById(sectionId);


if(element) {
element.scrollIntoView(); // scroll to a particular element
}
}

在 html 文件:

<a [fragment]="test1" [routerLink]="['./']">Go to Test 1 section</a>


<section id="test1">...</section>
<section id="test2">...</section>

档案里写着:

export class PageComponent implements AfterViewInit, OnDestroy {


private destroy$$ = new Subject();
private fragment$$ = new BehaviorSubject<string | null>(null);
private fragment$ = this.fragment$$.asObservable();


constructor(private route: ActivatedRoute) {
this.route.fragment.pipe(takeUntil(this.destroy$$)).subscribe(fragment => {
this.fragment$$.next(fragment);
});
}


public ngAfterViewInit(): void {
this.fragment$.pipe(takeUntil(this.destroy$$)).subscribe(fragment => {
if (!!fragment) {
document.querySelector('#' + fragment).scrollIntoView();
}
});
}


public ngOnDestroy(): void {
this.destroy$$.next();
this.destroy$$.complete();
}
}