angular 页面内跳转(锚点定位被顶部固定导航栏遮住)踩坑记录

苗大 · 2021-8-27 · 次阅读


前言:

angular页面内跳转,需求是按钮点击后跳转到对应名字标题的位置,标题已设置同名id,且跳转位置不能被顶部固定导航栏遮住。
一开始是用a标签href跳转,标题css加了:target伪类(《锚点定位被顶部固定导航栏遮住的解决方案》文章中的方法4)完美解决,但是后来由于路由前加了服务标识区分(xxx-frontend-web),像这样:

http://localhost:4200/xxx-frontend-web/#/home#我是标题

导致了a标签跳转失效,a标签的只能跳到http://localhost:4200/home#我是标题,其实也可以在所有a标签href里加服务区分标识,但是,这种方法还是太蠢了。。。
然后找到的方法是用js原生的scrollIntoView,配合在标题css上加一个padding-top:140px(那篇文章的方法2),凑合解决。

const element = document.querySelector('#' + id);
if (element) {
  element.scrollIntoView({ behavior: 'smooth' });
  // 路由跳转(让url也加上#id)
  const _path = this.getUrlRelativePath();
  this.router.navigate([_path], { fragment: id });
}

没过几天,开始做面包屑,发现面包屑正好被标题的padding挡住按不到。。。看来还是得找替代方法

解决方法1

终于在stackoverflow上大佬的回答里找到了不用加padding的解决方案:

const element = document.querySelector('#' + id);
if (element) {
  const yOffset = -140;
  const y = element.getBoundingClientRect().top + window.pageYOffset + yOffset;

  window.scrollTo({top: y, behavior: 'smooth'});
  // 路由跳转(让url也加上#id)
  const _path = this.getUrlRelativePath();
  this.router.navigate([_path], { fragment: id });
}

解决方法2

在查询过程中发现angular Api中有页面内滚动的方法:ViewportScroller,试了一下发现比原生js的更好用:

//需要先在构造时候引入
constructor(private _vps: ViewportScroller) {}
//然后方法中即可直接调用:
// 设置滚动偏差([x,y], 此处y是header高度)
this._vps.setOffset([0, 140]);
// 滚动到id位置
this._vps.scrollToAnchor(id);
// 路由跳转
const _path = this.getUrlRelativePath();
this.router.navigate([_path], { fragment: id });

2021/8/30 更新 解决方法2改

解决方法2中的setOffset可以在Angular引入Router时的初始化参数里设置:

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled',
      anchorScrolling: 'enabled',
      scrollOffset: [0, 0],
    })
  ]
})

1、scrollPositionRestoration 可能的选项有:

  • disabled:什么也不做(当前默认);
  • top:导航后自动回到页面顶部;
  • enabled:(后退时)恢复到原始位置或(前进时)基于 anchorScrolling 选项的元素位置(否则置顶);

2、anchorScrolling 可能的选项有:

  • disabled:什么也不做(当前默认);
  • enabled:跳转到当前 Fragment 对应元素的位置(如果有的话);

3、scrollOffset 用于设定置顶的位置。

参考资料&鸣谢:


我不是天生的王者,但我骨子里流动着不让我低头的血液!