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