js:锚点滚动到页面对应区域

锚点跳转到对应页面的区域使用 scrollIntoView

// anchor即你要跳转到的元素
anchor.scrollIntoView({
  behavior: "smooth",  
  block: "center",  
  inline: "nearest"  
});

1、behavior:定义滚动行为。它可以设置为 “auto” 或 “smooth”。默认是 “auto”。
“auto”:立即跳转到元素,没有动画。
“smooth”:平滑地滚动到元素,有动画效果。

2、block:定义垂直方向的对齐方式。它可以设置为 “start”、“center”、“end” 或 “nearest”。默认是 “start”。
“start”:元素的顶部与视口的顶部对齐。
“center”:元素的中心与视口的中心对齐。
“end”:元素的底部与视口的底部对齐。
“nearest”:滚动到最接近视口的位置。

3、inline:定义水平方向的对齐方式。它可以设置为 “start”、“center”、“end” 或 “nearest”。默认是 “nearest”。
“start”:元素的左侧与视口的左侧对齐。
“center”:元素的中心与视口的中心对齐。
“end”:元素的右侧与视口的右侧对齐。
“nearest”:滚动到最接近视口的位置。

下面代码主要是针对具体项目可能遇到的一些问题,主要是我自己做一个记录,上面其实已经给出了答案,大家酌情看下面的内容:
在这里插入图片描述

监听滚动的盒子 html 结构

<div ref="scrollFun">
  <div class="compute-nav-num" id="navEle1"></div>
  <div class="compute-nav-num" id="navEle2"></div>
  <div class="compute-nav-num" id="navEle3"></div>
</div>

监听滚动的盒子js逻辑

const scrollFun = ref();
onMounted(() => {
  scrollFun.value.addEventListener('scroll', handleScroll);
});
onBeforeUnmount(() => {
  scrollFun.value.removeEventListener('scroll', handleScroll)
});
const handleScroll = () => {
  handleScroll();
};
const closeEventFun = () => {
  scrollFun.value.removeEventListener('scroll', handleScroll);
}
const openEventFun = () => {
  scrollFun.value.addEventListener('scroll', handleScroll);
}

const handleScroll = () => {
  if (scrollTimer) {
    clearTimeout(scrollTimer);
  }
  scrollTimer = setTimeout(() => {
    // compute-nav-num 这个类名是为了收集所有滚动的盒子里的子集
    const viewList = document.querySelectorAll('.compute-nav-num');
    let active = 0;
    if (viewList.length === 0) return;
    for (let i = 0; i < viewList.length; i++) {
      const top = (scrollFun as any).value.scrollTop + 30;
      if (i === 0) {
        const next = (viewList[i + 1] as any).offsetTop;
        if (top < next) {
          active = i;
          break;
        }
      } else {
        const target = (viewList[i] as any).offsetTop;
        const next = (viewList[i + 1] as any).offsetTop;
        if (top > target || top == target) {
          if (top < next) {
            active = i;
            break;
          }
        }
      }
    }
    activeNavIndex.value = active + 1;
  }, 50);
};
const routerClick = (obj: any) => {
  // i是点亮导航栏的
  activeNavIndex.value = Number(obj.i);
  // id是固定的 是控制滚动的
  viewActive(obj.id);
};
const viewActive = (id: any) => {
  // 当点击导航栏时清除滚动监听,这是因为scrollIntoView事件,也会触发滚动监听
  // 关闭主要是因为,最下面总有几个特别小的盒子,滚动其实是无法点亮对应导航栏的
  // 点击属于最后几个小盒子对应的导航栏时,如果滚动监听也触发了,那最后算的 activeNavIndex肯定不对
  closeEventFun();
  const anchor = document.querySelector('#navEle' + id);
  if (anchor) {
    anchor.scrollIntoView({
      behavior: 'smooth'
    });
  }
  // 下面的事件既是滚动的一个事件间隔,争取在滚动结束后,再放开监听
  setTimeout(() => {
    openEventFun();
  }, 850);
}

导航栏组件

// 这里的数据 id之所以写这里,是为了固定id数值,这样是为了适应,导航栏有时在某些情况下
// 需要隐藏一些,这时 index 就是随机的,加上固定id,点击传出,这样 querySelector 才能找到
let navListObj: any = reactive([
  {
    name: '工单',
    id: '1',
    img: orderInfo,
    imgActive: orderInfoActive
  },
  {
    name: '来电',
    id: '2',
    img: phoneInfo,
    imgActive: phoneInfoActive
  }
]);
// 点击传出参数
const emit = defineEmits(["routerClick"]);
const routerClick = (id: any, i: any) => {
  emit("routerClick", {id: id, i: i});
}
<div class="affix-nav">
    <ul>
      <li v-for="(obj, i) in navListObj" :key="i">
        <a @click="routerClick(obj.id, i + 1)" :class="activeNavIndex === i + 1 ? 'active' : ''">
          <img :src="activeNavIndex === (i + 1) ? obj.imgActive : obj.img" alt="">
          <span>{{ (obj as any).name1 }}</span>
          <span v-if="(obj as any).name2">{{ (obj as any).name2 }}</span>
        </a>
      </li>
    </ul>
  </div>
.affix-nav {
  max-height: 60%;
  position: absolute;
  right: 5px;
  top: 0;
  bottom: 0;
  margin: auto;
  z-index: 1000;
  overflow: auto;
  background-color: #fff;
  box-shadow: -2px 2px 10px rgba(0, 0, 0, .5);
  padding: 20px 8px;
  border-radius: 5px;
  ul {
    padding-left: 0;
  }
  li a {
    text-align: center;
    display: block;
    font-size: 12px;
    margin-bottom: 10px;
    cursor: pointer;
    img {
      position: relative;
      right: 0;
      left: 0;
      margin: auto;
      padding-bottom: 5px;
    }
    span {
      color: #BBBBBB;
      line-height: 16px;
      display: block;
    }
  }
  .active span {
    color: #f00;
  }
}
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值