Answers:
更新资料
现在支持
<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进行了跟踪
01
或者100
没有有效的CSS选择器。您可能需要添加字母或其他内容以使其成为有效的选择器。因此,您仍然会01
像片段一样通过,但是该对象id
必须是类似的东西d01
,然后document.querySelector('#d'+id)
才能匹配。
尽管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(true); }
}
}
});
}
}
请注意,这是一种解决方法!请关注此github问题以获取将来的更新。感谢Victor Savkin提供的解决方案!
"['../faq']"
该值,否则它将尝试跳转到/ faq /#anchor的/ faq / faq /#anchor。这是正确的方法还是在routerlink中引用当前页面的方法更优雅?另外,document.querySelector("#" + tree.fragment);
给我一个无效的选择器错误。您确定这是正确的吗?谢谢
<a [routerLink]="['/faq']" fragment="section6">
吗?
对不起,回答太晚了;Angular Routing文档中有一个预定义的功能,该功能可帮助我们使用带有标签的路由将其定位到页面锚,即 anchorScrolling:'enabled'
第1步: -首先导入RouterModule在app.module.ts文件: -
imports:[
BrowserModule,
FormsModule,
RouterModule.forRoot(routes,{
anchorScrolling: 'enabled'
})
],
步骤2:-转到HTML页面,创建导航并添加两个重要属性,例如[routerLink]和fragment,以匹配相应的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 / 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>
供您参考,我通过创建一个小示例来添加了以下示例,该示例有助于解决您的问题。
scrollPositionRestoration: 'enabled',
下anchorScrolling选项:)
有点晚了,但是我发现这是可行的答案:
<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,并且一切顺利。
document.querySelector ( "#" + f )
给我一个错误,因为它需要选择器而不是字符串。
element.scrollIntoView()
不传递element
给函数)。要使其平滑,请使用:element.scrollIntoView({block: "end", behavior: "smooth"})
。
onAnchorClick()
,我们必须通过一个布尔值,scrollIntoView: if (element) { element.scrollIntoView(true); }
。现在,我可以在同一链接上单击两次并滚动作品
上面的解决方案对我不起作用...这个做到了:
首先,准备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 } );
}
}
所有其他答案将适用于Angular版本<6.1。但是,如果您拥有最新版本,则无需进行这些丑陋的修改,因为Angular已解决了该问题。
您需要做的就是scrollOffset
使用RouterModule.forRoot
method 的第二个参数设置。
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
scrollOffset: [0, 64] // [x, y]
})
],
exports: [RouterModule]
})
export class AppRoutingModule {}
在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();
}
}
加上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 )
});
}
element.scrollIntoView()
或element.scrollIntoView(true)
。您的版本无法为我编译(可能是因为strictNullChecks?)。
阅读完所有解决方案后,我寻找了一个组件,该组件完全符合原始问题的要求:滚动到锚定链接。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)="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“保护”的任何动态数据。更改路线时,也可以将其滚动到页面顶部-仅提供默认的顶部锚标签。
如果将那些元素ID附加到url上没有关系,则应考虑查看以下链接:
// 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
}
}
这是引用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标签的页面,则允许用户直接滚动到元素。
但是在这种情况下,我已经订阅了Fragment路由,ngAfterViewChecked
但是ngAfterViewChecked()
每次都被连续调用ngDoCheck
,并且不允许用户滚动到顶部,因此routeFragmentSubscription.unsubscribe
在视图滚动到元素后超时0毫秒后被调用。
另外,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);
}
这个为我工作!这个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
!
不像其他的答案,我会另外还加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();
}
});
}
我遇到过同样的问题。解决方案:使用View port Scroller 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);
}
}
我刚刚测试了nmp中可用的非常有用的插件-ngx-scroll-to,对我来说非常有用。但是,它是为Angular 4+设计的,但是也许有人会觉得这个答案有用。
我尝试了大多数这些解决方案,但是遇到了问题,留下了另一个无法使用的片段,因此我做了一些与众不同的事情,可以100%工作,并且摆脱了URL中的丑陋哈希。
tl; dr这是到目前为止我所见不到的更好的方法。
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();
}
}
123
是在问题)假设路由路径期望的参数等{ path: 'users/:id', ....}