简体   繁体   English

添加 class 在滚动时处于活动状态。 香草JS

[英]Add class active on scroll. Vanilla JS

I'm new to vanilla js.我是香草js的新手。 I have a navbar with links to sections.我有一个带有部分链接的导航栏。 I want to make the class active as soon as the section becomes active.我想在该部分激活后立即激活 class。 If there are no active section, then remove the active class.如果没有活动部分,则移除活动 class。 Found such a script , but there is one drawback.找到了这样一个脚本,但是有一个缺点。 If I am in an inactive section, the active class will remain with the previous active section.如果我处于非活动部分,则活动 class 将保留在前一个活动部分。

 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>

PSLook at the last line, there is changeLinkState . PS看最后一行,有changeLinkState Should it be without parentheses () ?它应该没有括号()吗? And inside while is empty, why?而里面while是空的,为什么?

The most minimal change you can make using the current design to implement the desired functionality is testing the section's height to ensure it's visible instead of unconditionally adding the active class to the nearest navigation link as in the current code.使用当前设计实现所需功能的最小更改是测试部分的高度以确保其可见,而不是像当前代码中那样无条件地将活动 class 添加到最近的导航链接。

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

Instead of:代替:

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

You can tweak the cutoff point with an offset like scrollY + 50 but hardcoding the number here seems non-ideal.您可以使用像scrollY + 50这样的偏移量来调整截止点,但在这里硬编码数字似乎并不理想。

Full code:完整代码:

 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>

Your other questions were addressed in the comments but I'll reiterate the answers here:您的其他问题已在评论中解决,但我将在这里重申答案:

  • No parentheses are used on changeLinkState because we're passing the function object itself to the callback to be invoked later. changeLinkState上没有使用括号,因为我们将 function object 本身传递给稍后调用的回调。 If we invoked it like changeLinkState() , we'd wind up passing undefined into the callback and prematurely firing the handler, as explained here .如果我们像changeLinkState()那样调用它,我们最终会将undefined传递给回调并过早地触发处理程序,如此所述。
  • while is empty because its block that manipulates the termination condition (ie --index ) is merged into the condition as shorthand, as described here . while是空的,因为它操纵终止条件(即--index )的块作为简写形式合并到条件中,如此所述。

Beyond that, there are multiple issues with the design I'll remark on briefly and leave as an exercise to the reader:除此之外,我将简要说明设计存在多个问题,并将其作为练习留给读者:

  • The bootstrap layout spreads the sidebar header across the whole page, so there's probably unintentional overlap between the header and the element.引导布局将侧边栏 header 扩展到整个页面,因此 header 和元素之间可能存在无意的重叠。 If the header had a background, content would be occluded.如果 header 有背景,则内容将被遮挡。 I'd revisit the structure here to ensure multiple, non-overlapping columns or a flow layout was used.我将重新审视这里的结构,以确保使用多个不重叠的列或流布局。
  • <section> tags should be in a parent container. <section>标签应该在父容器中。
  • CSS properties shouldn't be camelCased . CSS 属性不应该是camelCased forJS is not a particularly clear class name. forJS不是特别明确的 class 名称。
  • scroll-y:auto; is an invalid CSS property.是无效的 CSS 属性。 Perhaps you meant overflow-y: auto;也许您的意思是overflow-y: auto; . .
  • The strategy of firing the scroll event listener and iterating the sections is somewhat primitive.触发滚动事件侦听器和迭代部分的策略有些原始。 Check out throttling and consider refactoring to use an Intersection Observer .查看throttling并考虑重构以使用Intersection Observer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM