我希望在我的Angular2页面上添加一些链接,点击后,会跳转到在该页面中的特定位置,就像普通主题标签一样。所以链接就像是
/users/123#userInfo
/users/123#userPhoto
/users/123#userLikes
等
我认为我不需要HashLocationStrategy,因为我对正常的Angular2方式很好,但如果我直接添加,链接实际上会跳转到根目录,而不是同一页面上的某个地方。任何方向都表示赞赏,谢谢。
答案 0 :(得分:101)
<强>更新强>
现在支持
<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) { }
}
<强>原始强>
进行了跟踪答案 1 :(得分:48)
虽然Günter's answer是正确的,但并未涵盖“跳转到”锚标记部分。
因此,除了:
<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); }
}
}
});
}
}
请注意,这是一种解决方法!关注this github issue以获取更新。致Victor Savkin提供解决方案的信用!
答案 2 :(得分:25)
有点晚了,但我发现这个答案有效:
<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,这应该是好的。
答案 3 :(得分:15)
以前的答案都不适合我。在最后的努力中,我尝试了我的模板:
<a (click)="onClick()">From Here</a>
<div id='foobar'>To Here</div>
用我的.ts:
onClick(){
let x = document.querySelector("#foobar");
if (x){
x.scrollIntoView();
}
}
它对预期的内部链接起作用。这实际上并不使用锚标记,因此它根本不会触及URL。
答案 4 :(得分:14)
很抱歉回答得太晚了; Angular Routing文档中有一个预定义的功能,该功能可帮助我们使用带有标签的路由进行页面锚定,即 anchorScrolling:'enabled'
步骤1:-:首先在app.module.ts文件中导入 RouterModule :-
imports:[
BrowserModule,
FormsModule,
RouterModule.forRoot(routes,{
anchorScrolling: 'enabled'
})
],
第2步:-转到HTML页面,创建导航并添加两个重要属性,例如 [routerLink] 和片段与各个 Div ID的匹配:-
<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步:-通过将 ID名称与片段匹配:-
<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>
作为参考,我通过创建一个小示例来添加以下示例,该示例有助于解决您的问题。
答案 5 :(得分:6)
上面的解决方案对我不起作用......这个做到了:
首先,准备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 } );
}
}
答案 6 :(得分:4)
将其用于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">
答案 7 :(得分:4)
所有其他答案将适用于Angular版本<6.1。但是,如果您拥有最新版本,则无需进行这些丑陋的修改,因为Angular已解决了该问题。
您需要做的就是使用scrollOffset
方法的第二个参数设置RouterModule.forRoot
。
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
scrollOffset: [0, 64] // [x, y]
})
],
exports: [RouterModule]
})
export class AppRoutingModule {}
答案 8 :(得分:3)
添加到Kalyoyan的answer,此订阅与路由器绑定,并将一直存在,直到页面完全刷新。订阅组件中的路由器事件时,请务必取消订阅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();
}
}
答案 9 :(得分:3)
我刚在我自己的网站上工作,所以我认为在这里发布我的解决方案是值得的。
<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 )
});
}
答案 10 :(得分:3)
在阅读了所有解决方案之后,我找到了一个组件,我找到了一个完全符合原始问题要求的组件:滚动到锚链接。 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 {
}
它对我来说非常好。
答案 11 :(得分:2)
适用于没有任何查询参数的网页的简单解决方案是浏览器后退/转发,路由器和深度链接兼容。
<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();
}
}
超时只是允许页面加载任何动态数据&#34; protected&#34;通过* ngIf。这也可用于在更改路线时滚动到页面顶部 - 只需提供默认的顶部锚标记。
答案 12 :(得分:2)
由于fragment属性仍然不提供锚滚动,因此这种解决方法对我有用:
<div [routerLink]="['somepath']" fragment="Test">
<a href="#Test">Jump to 'Test' anchor </a>
</div>
答案 13 :(得分:1)
我有同样的问题。 解决方案:使用查看端口滚动器https://angular.io/api/common/ViewportScroller#scrolltoanchor
-app-routing.module.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);
}
}
答案 14 :(得分:1)
这个为我工作!这个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>
我的ts文件:
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();
}
}
别忘了导入ViewChildren
,QueryList
等。并添加一些构造函数ActivatedRoute
!
答案 15 :(得分:1)
以下是参考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
订阅了路径片段,但每ngAfterViewChecked()
个ngDoCheck
连续调用它,并且它不允许用户滚动回顶部,因此,在视图滚动到元素后,在超时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);
}
答案 16 :(得分:1)
如果将这些元素ID附加到url没关系,则应考虑查看以下链接:
Angular 2 - Anchor Links to Element on Current Page
// 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
}
}
答案 17 :(得分:1)
在html文件中:
<a [fragment]="test1" [routerLink]="['./']">Go to Test 1 section</a>
<section id="test1">...</section>
<section id="test2">...</section>
在ts文件中:
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();
}
}
答案 18 :(得分:0)
我尝试了大多数这些解决方案,但遇到了问题,留下并返回另一个片段,它不起作用,所以我做了一些有点不同的工作100%,并摆脱了URL中的丑陋哈希。 / p>
;这里的博士比我到目前为止看到的方式更好。
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();
}
}
答案 19 :(得分:0)
我刚刚在nmp中测试了非常有用的插件 - ngx-scroll-to,这对我很有用。然而,它是为Angular 4+设计的,但也许有人会觉得这个答案很有帮助。
答案 20 :(得分:0)
与其他答案不同,我还要另外添加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();
}
});
}