【问题标题】:Add class active on scroll. Vanilla JS添加滚动时活动的类。香草JS
【发布时间】:2021-02-12 05:06:07
【问题描述】:

我是香草 js 的新手。我有一个带有部分链接的导航栏。我想在该部分激活后立即激活该类。如果没有活动部分,则删除活动类。找到了这样一个script,但是有一个缺点。如果我在非活动部分,活动类将保留在前一个活动部分。

const links = document.querySelectorAll('.nav-link');
const sections = document.querySelectorAll('.forJS');
  function changeLinkState() {
    let index = sections.length;

    while(--index && window.scrollY + 50 < sections[index].offsetTop) {}

    links.forEach((link) => link.classList.remove('active'));
    links[index].classList.add('active');
  }

changeLinkState();
window.addEventListener('scroll', changeLinkState);
section{
height:100vh;
scroll-y:auto;
}
.nav-link.active{
  color: red;
}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<header class="fixed-top">
  <nav class="navbar navbar-expand-lg navCustom">
    <div class="container">

          <ul class="navbar-nav justify-content-center">
            <li class="nav-item">
              <a class="nav-link" href="#main">Main</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#about">About us</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#portfolio">Portfolio</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#contacts">Contacts</a>
            </li>
          </ul>
    </div>
  </nav>
</header>

<section class="forJS text-center">Some info 1</section>
<section class="forJS text-center">Some info 2</section>
<section class="forJS text-center">Some info 3</section>
<section class="text-center">Some info 4</section>
<section class="text-center">Some info 5</section>
<section class="text-center">Some info 6</section>
<section class="text-center">Some info 7</section>
<section class="text-center">Some info 8</section>
<section class="text-center">Some info 9</section>
<section class="forJS text-center">Some info 10</section>
</body>

P.S.看最后一行,有changeLinkState。是不是应该不带括号()? 而且while里面是空的,为什么?

【问题讨论】:

  • Why While is Empty 阅读这里
  • 一切都清楚了,谢谢!如果没有部分处于活动状态,只需弄清楚如何删除类active
  • NO 部分处于活动状态是什么意思?当您滚动到最后一个部分,即第 10 部分时,您无法滚动,因此它处于活动状态。只需将border: 1px solid black; 添加到您的section CSS,您就会发现哪个部分处于活动状态。
  • 如果用户在第 4 到第 9 节中,我不希望 nav-linksactive 类。我希望 nav-link 有一个 active 类,只有当我们在这个 nav-link 链接到的 section 上时。

标签: javascript html css


【解决方案1】:

使用当前设计实现所需功能的最小更改是测试部分的高度以确保其可见,而不是像当前代码中那样无条件地将活动类添加到最近的导航链接。

if (window.scrollY - sections[index].offsetHeight < 
      sections[index].offsetTop) {
  links[index].classList.add('active');
}

代替:

links[index].classList.add('active');

您可以使用scrollY + 50 之类的偏移量来调整截止点,但在这里硬编码数字似乎并不理想。

完整代码:

const links = document.querySelectorAll('.nav-link');
const sections = document.querySelectorAll('.forJS');

function changeLinkState() {
  let index = sections.length;

  while (--index && window.scrollY + 50 < sections[index].offsetTop) {}

  links.forEach((link) => link.classList.remove('active'));

  // add the active class if within visible height of the element
  if (scrollY - sections[index].offsetHeight <
        sections[index].offsetTop) {
    links[index].classList.add('active');
  }
}

changeLinkState();
window.addEventListener('scroll', changeLinkState);
section {
  height: 100vh;
}

.nav-link.active {
  color: red;
}

section {
  border: 1px solid #555;
}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" />

<body>
  <header class="fixed-top">
    <nav class="navbar navbar-expand-lg navCustom">
      <div class="container">
        <ul class="navbar-nav justify-content-center">
          <li class="nav-item">
            <a class="nav-link" href="#main">Main</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#about">About us</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#portfolio">Portfolio</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#contacts">Contacts</a>
          </li>
        </ul>
      </div>
    </nav>
  </header>

  <section class="forJS text-center">Some info 1</section>
  <section class="forJS text-center">Some info 2</section>
  <section class="forJS text-center">Some info 3</section>
  <section class="text-center">Some info 4</section>
  <section class="text-center">Some info 5</section>
  <section class="text-center">Some info 6</section>
  <section class="text-center">Some info 7</section>
  <section class="text-center">Some info 8</section>
  <section class="text-center">Some info 9</section>
  <section class="forJS text-center">Some info 10</section>
</body>

您的其他问题已在 cmets 中得到解决,但我将在此重申答案:

  • changeLinkState 上没有使用括号,因为我们将函数对象本身传递给回调以供稍后调用。如果我们像changeLinkState() 那样调用它,我们最终会将undefined 传递到回调中并过早地触发处理程序,正如here 所解释的那样。
  • while 是空的,因为它操纵终止条件的块(即--index)作为简写形式合并到条件中,如here 所述。

除此之外,我将简要说明设计中存在的多个问题,并将作为练习留给读者:

  • 引导布局将侧边栏标题扩展到整个页面,因此标题和元素之间可能存在无意的重叠。如果标题有背景,则内容将被遮挡。我会重新审视这里的结构,以确保使用了多个不重叠的列或流布局。
  • &lt;section&gt; 标签应该在父容器中。
  • CSS 属性不应为camelCasedforJS 不是一个特别清楚的类名。
  • scroll-y:auto; 是无效的 CSS 属性。也许你的意思是overflow-y: auto;
  • 触发滚动事件侦听器和迭代部分的策略有些原始。查看throttling 并考虑重构以使用Intersection Observer

【讨论】:

    猜你喜欢
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多