📜  使用 javascript 在滚动时突出显示导航菜单(1)

📅  最后修改于: 2023-12-03 15:06:47.486000             🧑  作者: Mango

使用 JavaScript 在滚动时突出显示导航菜单

在网页开发中,常常需要实现导航菜单在滚动时的效果,让用户更方便地浏览内容。本文将介绍使用 JavaScript 实现导航菜单在滚动时的突出显示效果。

实现原理

实现导航菜单在滚动时的突出显示效果的原理是监听窗口滚动事件,根据当前窗口的滚动位置确定当前所在的章节,然后选中对应的导航菜单项。

实现步骤
1. 编写 HTML 结构

首先,我们需要在 HTML 中定义导航菜单和对应的内容章节,为导航菜单的每个项添加一个唯一的标识符,方便后面的 JavaScript 代码快速定位章节。

<nav>
  <ul>
    <li><a href="#section1">Section 1</a></li>
    <li><a href="#section2">Section 2</a></li>
    <li><a href="#section3">Section 3</a></li>
    <li><a href="#section4">Section 4</a></li>
    <li><a href="#section5">Section 5</a></li>
  </ul>
</nav>

<section id="section1">
  <h2>Section 1</h2>
  <p>Content of section 1 goes here.</p>
</section>

<section id="section2">
  <h2>Section 2</h2>
  <p>Content of section 2 goes here.</p>
</section>

<section id="section3">
  <h2>Section 3</h2>
  <p>Content of section 3 goes here.</p>
</section>

<section id="section4">
  <h2>Section 4</h2>
  <p>Content of section 4 goes here.</p>
</section>

<section id="section5">
  <h2>Section 5</h2>
  <p>Content of section 5 goes here.</p>
</section>
2. 添加 CSS 样式

为导航菜单和内容章节添加样式,使其更容易辨认,并控制它们的显示状态。

nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  z-index: 100;
}

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  justify-content: space-between;
}

nav li {
  margin: 0 1rem;
}

nav a {
  text-decoration: none;
  color: #222;
  font-size: 1.2rem;
}

nav a.active {
  color: #0077cc;
  border-bottom: 2px solid #0077cc;
}

section {
  padding: 5rem 0;
  text-align: center;
}

section h2 {
  font-size: 2rem;
  margin-bottom: 2rem;
}

section p {
  font-size: 1.2rem;
  line-height: 1.5;
  color: #666;
}
3. 编写 JavaScript 代码

监听窗口滚动事件,并根据当前窗口的滚动位置计算当前所在的章节,然后选中对应的导航菜单项。在设计导航菜单项的激活状态时,可以通过为对应的导航菜单项添加一个“active”类来实现。

const nav = document.querySelector('nav');
const sections = document.querySelectorAll('section');
const navHeight = nav.offsetHeight;

window.addEventListener('scroll', () => {
  let current = '';

  sections.forEach((section) => {
    const sectionTop = section.offsetTop;
    const sectionHeight = section.offsetHeight;

    if (pageYOffset >= sectionTop - navHeight) {
      current = section.getAttribute('id');
    }
  });

  const menuItems = document.querySelectorAll('nav a');

  menuItems.forEach((item) => {
    item.classList.remove('active');
    if (item.getAttribute('href').substr(1) === current) {
      item.classList.add('active');
    }
  });
});
4. 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Scroll Spy Menu</title>
  <style>
    nav {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      background-color: #fff;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      z-index: 100;
    }

    nav ul {
      margin: 0;
      padding: 0;
      list-style: none;
      display: flex;
      justify-content: space-between;
    }

    nav li {
      margin: 0 1rem;
    }

    nav a {
      text-decoration: none;
      color: #222;
      font-size: 1.2rem;
    }

    nav a.active {
      color: #0077cc;
      border-bottom: 2px solid #0077cc;
    }

    section {
      padding: 5rem 0;
      text-align: center;
    }

    section h2 {
      font-size: 2rem;
      margin-bottom: 2rem;
    }

    section p {
      font-size: 1.2rem;
      line-height: 1.5;
      color: #666;
    }
  </style>
</head>
<body>
  <nav>
    <ul>
      <li><a href="#section1">Section 1</a></li>
      <li><a href="#section2">Section 2</a></li>
      <li><a href="#section3">Section 3</a></li>
      <li><a href="#section4">Section 4</a></li>
      <li><a href="#section5">Section 5</a></li>
    </ul>
  </nav>

  <section id="section1">
    <h2>Section 1</h2>
    <p>Content of section 1 goes here.</p>
  </section>

  <section id="section2">
    <h2>Section 2</h2>
    <p>Content of section 2 goes here.</p>
  </section>

  <section id="section3">
    <h2>Section 3</h2>
    <p>Content of section 3 goes here.</p>
  </section>

  <section id="section4">
    <h2>Section 4</h2>
    <p>Content of section 4 goes here.</p>
  </section>

  <section id="section5">
    <h2>Section 5</h2>
    <p>Content of section 5 goes here.</p>
  </section>

  <script>
    const nav = document.querySelector('nav');
    const sections = document.querySelectorAll('section');
    const navHeight = nav.offsetHeight;

    window.addEventListener('scroll', () => {
      let current = '';

      sections.forEach((section) => {
        const sectionTop = section.offsetTop;
        const sectionHeight = section.offsetHeight;

        if (pageYOffset >= sectionTop - navHeight) {
          current = section.getAttribute('id');
        }
      });

      const menuItems = document.querySelectorAll('nav a');

      menuItems.forEach((item) => {
        item.classList.remove('active');
        if (item.getAttribute('href').substr(1) === current) {
          item.classList.add('active');
        }
      });
    });
  </script>
</body>
</html>

代码详细说明请参考代码注释。