可以使用RxJS的fromEvent()和combineLatest()函数结合window.scrollY来实现滚动到锚点的精确控制。
示例代码:
import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core'; import { ViewportScroller } from '@angular/common'; import { fromEvent, combineLatest, Subscription } from 'rxjs'; import { filter, map } from 'rxjs/operators';
@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit, AfterViewInit, OnDestroy { private scrollSubscription: Subscription;
constructor(private viewportScroller: ViewportScroller) {}
ngOnInit(): void { // 订阅窗口滚动事件和路由改变事件 const scroll$ = fromEvent(window, 'scroll').pipe( map(() => window.scrollY) ); const route$ = this.router.events.pipe( filter(event => event instanceof NavigationEnd) );
// 从锚点获取滚动位置
const anchor$ = combineLatest([scroll$, route$]).pipe(
map(([scrollY]) => {
return this.viewportScroller.getScrollPosition()[1] + scrollY;
})
);
// 滚动到锚点
this.scrollSubscription = this.route.fragment.pipe(
filter(fragment => fragment !== null),
map(fragment => document.querySelector(`#${fragment}`)),
filter(element => !!element),
map(element => {
const rect = element.getBoundingClientRect();
const scrollY = anchor$.getValue();
return scrollY + rect.top - 8;
}),
map(scrollY => [scrollY]),
map(([scrollY]) => {
return [0, scrollY];
})
).subscribe(([x, y]) => {
this.viewportScroller.scrollToPosition([x, y]);
});
}
ngAfterViewInit(): void {
// 初始位置
const anchor = this.route.snapshot.fragment;
if (anchor) {
setTimeout(() => {
const element = document.querySelector(#${anchor}
);
if (element) {
const y = element.getBoundingClientRect().top + window