Angular2使用Hashtag路由到页面定位

我希望在我的Angular2页面添加一些链接,当点击时,将跳转到该页面中的特定位置,如正常的主题标签所做的。 所以这个链接就是这样的

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

等等

我不认为我需要HashLocationStrategy,因为我用正常的Angular2方法很好,但是如果直接添加,链接实际上会跳转到根目录,而不是在同一页上的某处。 任何方向感谢,谢谢。

更新

现在支持

 <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进行跟踪;

虽然Günter的答案是正确的, 但它并不包括“跳转到”锚标签部分

因此,除了:

 <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(element); } } } }); } } 

请注意,这是一个解决方法 ! 按照这个github问题进行未来的更新。 感谢Victor Savkin提供的解决scheme!

有点晚,但这里有一个答案,我发现这样的作品:

 <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上面的解决scheme,以便它也可以使用:

 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,它应该是一切都好。

资源

在阅读了所有的解决scheme之后,我查找了一个组件,然后find一个完全符合原始问题要求的组件:滚动到锚链接。 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 { } 

它对我来说真的很好。

上面的解决scheme不适合我…这一个做到了:

首先,准备MyAppComponent自动滚动ngAfterViewChecked()

 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 ); } } } ); } } } 

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

 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 } ); } } 

再加上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(); } } 

由于fragment属性仍然不提供锚点滚动,所以这个解决方法对我来说是个窍门:

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

没有以前的答案为我工作。 在最后的努力中,我尝试了我的模板:

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

有了这个在我的.ts:

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

它和内部链接的预期一样。 这实际上并不使用锚标签,因此根本不会触及URL。

这里是另一个解决方法,参考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); } } 

这允许用户直接滚动到元素,如果用户直接login在url中有标签的页面。

但在这种情况下,我已经在ngAfterViewChecked订阅了路由片段,但ngAfterViewChecked()每次ngDoCheck被连续ngDoCheck ,并且不允许用户回滚到顶部,所以在查看之后超过0 routeFragmentSubscription.unsubscribe后调用routeFragmentSubscription.unsubscribe滚动到元素。

另外gotoHashtag方法被定义为在用户特别点击锚标签时滚动到元素。

更新:

如果url有querystrings, [routerLink]="['self-route', id]"将不会保留querystrings。 我尝试了以下解决方法:

 <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); } 

我刚刚在我自己的网站上工作,所以我觉得这是值得在这里发布我的解决scheme。

 <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 ) }); } 

一个简单的解决scheme,适用于没有任何查询参数的页面,是浏览器后退/前进,路由器和深度链接兼容。

 <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“保护”的任何dynamic数据。 这也可以用来滚动到页面的顶部时更改路由 – 只是提供一个默认的顶部锚定标记。