Vanilla JS在滚动重构时更改链接的活动状态 [英] Vanilla JS change active state of links when scrolling refactoring

查看:63
本文介绍了Vanilla JS在滚动重构时更改链接的活动状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从即将进行的项目中放弃jQuery.我找到了一种使用纯Vanilla JS在滚动上创建粘性导航的方法,并希望导航中的链接在到达相应部分时更改其活动状态.

下面是我想出的可行解决方案,但是我确信可以改进代码以编程方式工作,而不必为每个元素选择和创建条件.

我也使用了许多不同的选择器,我很确定必须有一种方法可以改善它,例如使用querySelectorAll并在forEach循环中添加eventListener,但是我可以也不能使它正常工作.感谢您的帮助!

 // select links
const allLinks = document.querySelectorAll('header nav ul li');
const linkTop = document.querySelector('#linkTop');
const linkAbout = document.querySelector('#linkAbout');
const linkServices = document.querySelector('#linkServices');
const linkClients = document.querySelector('#linkClients');
const linkContact = document.querySelector('#linkContact');
// select sections
const sectionTop = document.querySelector('#top');
const sectionAbout = document.querySelector('#about');
const sectionServices = document.querySelector('#services');
const sectionClients = document.querySelector('#clients');
const sectionContact = document.querySelector('#contact');

function changeLinkState() {
  // home
  if (window.scrollY >= sectionTop.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkTop.classList.add('active');
  }
  // about
  if (window.scrollY >= sectionAbout.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkAbout.classList.add('active');
  }
  // services
  if (window.scrollY >= sectionServices.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkServices.classList.add('active');
  }
  clients
  if (window.scrollY >= sectionClients.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkClients.classList.add('active');
  }
  contact
  if (window.scrollY >= sectionContact.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkContact.classList.add('active');
  }
}

window.addEventListener('scroll', changeLinkState); 

 <nav>
  <ul>
    <li id="linkTop">
      <a href="#top">Home</a>
    </li>
    <li id="linkAbout">
      <a href="#about">About Us</a>
    </li>
    <li id="linkServices">
      <a href="#services">Services</a>
    </li>
    <li id="linkClients">
      <a href="#clients">Clients</a>
    </li>
    <li id="linkContact">
      <a href="#contact">Contact</a>
    </li>
  </ul>
</nav> 

非常感谢!

解决方案

您可以使用document.querySelectorAll()获取所有部分和链接.滚动浏览时,从最后到第一部分遍历该部分的列表,直到找到匹配的部分.然后从所有链接中删除.active类,并将其添加到活动index处的链接中.

注意:您应使用限制以防止调用一秒钟内多次changeLinkState.另一种选择是使用交集观察者API .

 const links = document.querySelectorAll('.links');
const sections = document.querySelectorAll('section');

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); 

 nav {
  position: fixed;
  top: 0;
  right: 0;
  width: 10em;
}

section {
  height: 100vh;
  margin: 1em 0;
  background: gold;
}

.active {
  background: silver;
} 

 <nav>
  <ul>
    <li id="linkTop" class="links">
      <a href="#top">Home</a>
    </li>
    <li id="linkAbout" class="links">
      <a href="#about">About Us</a>
    </li>
    <li id="linkServices" class="links">
      <a href="#services">Services</a>
    </li>
    <li id="linkClients" class="links">
      <a href="#clients">Clients</a>
    </li>
    <li id="linkContact" class="links">
      <a href="#contact">Contact</a>
    </li>
  </ul>
</nav>

<section>
  Home
</section>

<section>
  About Us
</section>

<section>
  Services
</section>

<section>
  Clients
</section>

<section>
  Contact
</section> 

I'm trying to ditch jQuery from my upcoming projects. I found a way to create a sticky nav on scroll with pure Vanilla JS, and wanted the links on my navigation to change their active state as they reach the corresponding sections.

Below is the working solution I came up with, but I'm sure that the code can be improved to work programmatically without having to select and create conditions for each element.

I'm also using a lot of different selectors, and I'm pretty sure there must be a way to improve that, maybe using querySelectorAll and adding an eventListener in a forEach loop, but I can't get that to work either. Thanks for your help!

// select links
const allLinks = document.querySelectorAll('header nav ul li');
const linkTop = document.querySelector('#linkTop');
const linkAbout = document.querySelector('#linkAbout');
const linkServices = document.querySelector('#linkServices');
const linkClients = document.querySelector('#linkClients');
const linkContact = document.querySelector('#linkContact');
// select sections
const sectionTop = document.querySelector('#top');
const sectionAbout = document.querySelector('#about');
const sectionServices = document.querySelector('#services');
const sectionClients = document.querySelector('#clients');
const sectionContact = document.querySelector('#contact');

function changeLinkState() {
  // home
  if (window.scrollY >= sectionTop.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkTop.classList.add('active');
  }
  // about
  if (window.scrollY >= sectionAbout.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkAbout.classList.add('active');
  }
  // services
  if (window.scrollY >= sectionServices.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkServices.classList.add('active');
  }
  clients
  if (window.scrollY >= sectionClients.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkClients.classList.add('active');
  }
  contact
  if (window.scrollY >= sectionContact.offsetTop) {
    allLinks.forEach(link => {
      link.classList.remove('active');
    });
    linkContact.classList.add('active');
  }
}

window.addEventListener('scroll', changeLinkState);

<nav>
  <ul>
    <li id="linkTop">
      <a href="#top">Home</a>
    </li>
    <li id="linkAbout">
      <a href="#about">About Us</a>
    </li>
    <li id="linkServices">
      <a href="#services">Services</a>
    </li>
    <li id="linkClients">
      <a href="#clients">Clients</a>
    </li>
    <li id="linkContact">
      <a href="#contact">Contact</a>
    </li>
  </ul>
</nav>

Thanks a lot!

解决方案

You can get all sections and links using document.querySelectorAll(). On scroll iterate the list of section from last to first, until you find one that matches. Then remove the .active class from all links, and add it to the link at the active index.

Note: You should use throttling to prevent the calling of changeLinkState multiple times in a second. Another option is to use the Intersection Observer API.

const links = document.querySelectorAll('.links');
const sections = document.querySelectorAll('section');

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);

nav {
  position: fixed;
  top: 0;
  right: 0;
  width: 10em;
}

section {
  height: 100vh;
  margin: 1em 0;
  background: gold;
}

.active {
  background: silver;
}

<nav>
  <ul>
    <li id="linkTop" class="links">
      <a href="#top">Home</a>
    </li>
    <li id="linkAbout" class="links">
      <a href="#about">About Us</a>
    </li>
    <li id="linkServices" class="links">
      <a href="#services">Services</a>
    </li>
    <li id="linkClients" class="links">
      <a href="#clients">Clients</a>
    </li>
    <li id="linkContact" class="links">
      <a href="#contact">Contact</a>
    </li>
  </ul>
</nav>

<section>
  Home
</section>

<section>
  About Us
</section>

<section>
  Services
</section>

<section>
  Clients
</section>

<section>
  Contact
</section>

这篇关于Vanilla JS在滚动重构时更改链接的活动状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆