JS原生实现浏览器滚动条滚动侧边栏高亮响应

目录

演示

需求

代码

css

html

script

代码解释

情况1

情况2

情况3

4、设置高亮

5、添加节流,减少触发回调的频率


演示

需求

左侧侧边栏link1、link2...所对应右侧内容link1-content、link2-content...,当鼠标点击link的时候,自动滚动到对应的content。手动拖动滚动条,左侧link进行高亮响应,当link2-content出现在视口的时候,左侧link2高亮,当link2-content和link3-content同时出现在视口的时候,左侧link2高亮(谁接近视口顶部,对应的link高亮)。

代码

css

      * {
        padding: 0;
        margin: 0;
        list-style: none;
      }
      .header {
        height: 200px;
        background-color: aqua;
      }
      .main {
        padding: 30px 0;
        display: flex;
        max-width: 1400px;
        margin: 0 auto;
        gap: 30px;
      }
      .main .sidebar {
        position: sticky;
        top: 0;
        width: 300px;
        align-self: start;
      }
      .main .content {
        display: flex;
        flex: 1;
        flex-direction: column;
        gap: 30px;
      }
      .main .content .content-item{
        background-color: aqua;
        height: 400px;
      }
      .main .sidebar ul li{
        padding: 20px 10px;
        background-color: aqua;
      }

      .main .sidebar ul li .active{
        color: red;
      }
      .footer {
        height: 200px;
        background-color: aqua;
      }

html

  <body>
    <section class="header"></section>
    <section class="main">
      <div class="sidebar">
        <ul>
          <li><a class="active" href="#content-item1">link1</a></li>
          <li><a href="#content-item2">link2</a></li> // 设置锚点所对应的content的id
          <li><a href="#content-item3">link3</a></li>
          <li><a href="#content-item4">link4</a></li>
          <li><a href="#content-item5">link5</a></li>
          <li><a href="#content-item6">link6</a></li>
        </ul>
      </div>
      <div class="content">
        <div id="content-item1" class="content-item">link1-content</div>
        <div id="content-item2" class="content-item">link2-content</div>
        <div id="content-item3" class="content-item">link3-content</div>
        <div id="content-item4" class="content-item">link4-content</div>
        <div id="content-item5" class="content-item">link5-content</div>
        <div id="content-item6" class="content-item">link6-content</div>
      </div>
    </section>
    <section class="footer"></section>
  </body>

script

      const allLinks = document.querySelectorAll("a:link");
      allLinks.forEach(function (link) {
        link.addEventListener("click", function (e) {
          e.preventDefault();
          const href = link.getAttribute("href");
          if ( href.startsWith("#")) {
            const sectionEl = document.querySelector(href);
            link_content.scrollIntoView({ behavior: "smooth" });
          }
        });
      });

设置link的href和link-content的id所对应,调用scrollIntoView({ behavior: "smooth" })自动滚动到对应的位置。

      const handleScroll = () => {
        const allContents = document.querySelectorAll(".content-item");
        const rectContent = [];
        allContents.forEach((ele) => {
          const eleRect = ele.getClientRects()[0];
          if (
            (eleRect.top >= 0 && window.innerHeight - eleRect.top >= eleRect.height) ||
            (eleRect.top < 0 && window.innerHeight <=             
            eleRect.height - Math.abs(eleRect.top)) ||
            eleRect.top >= 0
          ) {
              rectContent.push(ele);
          }
        });
        let linkId
        if (rectContent[0]) linkId = rectContent[0].id
        allLinks.forEach(link => link.classList.remove('active'))
        const linkDom = document.querySelector(`a[href="#${linkId}"]`)
        linkDom.classList.add('active')
      }
      window.addEventListener("scroll", function() {
        throttle(handleScroll, 100)();
      });
      window.addEventListener('mouseup', function() {
        throttle(handleScroll, 100)();
      });

代码解释

浏览器滚动,每次滚动触发scroll回调

情况1

 link-content1和link-content2都完全出现在视口中,谁接近视口顶部,对应的link高亮

情况2

如果情况1没有命中,则判断是否有元素占满整个屏幕,link-content(link-content2)完全占满整个视口

情况3

都没有完全出现在视口或者完全沾满视口,则取出现在第一个link-content与视口关系top > 0的值

4、设置高亮

        let linkId
        if (rectContent[0]) linkId = rectContent[0].id
        allLinks.forEach(link => link.classList.remove('active'))
        const linkDom = document.querySelector(`a[href="#${linkId}"]`)
        linkDom.classList.add('active')

找到存储在数组的第一项link-content,获取id,根据id获取对应的侧边栏link,清空之前设置的link的类active,为对应的link添加类active。

5、添加节流,减少触发回调的频率

      const throttle = (fn, delay) => {
        let lastExecuted = 0;
        return function() {
          const now = Date.now();
          if (now - lastExecuted > delay) {
            fn();
            lastExecuted = now;
          }
        }
      }

      window.addEventListener("scroll", function() {
        throttle(handleScroll, 100)();
      });
      window.addEventListener('mouseup', function() {
        throttle(handleScroll, 100)();
      });

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值