首页
Preview

vue3实现锚点跳转与滚动监听

需要实现的效果如下:

  1. 左侧分类导航栏:点击左侧分类时,页面会滚动到对应的分类区域,同时更新选中状态(高亮)。
  2. 右侧内容区:显示每个分类的具体子类别,右侧内容根据滚动位置动态更新左侧导航的选中状态。
  3. 路由更新:地址栏的 query 参数随导航栏选中状态动态更新(如 ?group=image)。

实现步骤

1. HTML 结构

<template>
  <div class="container">
    <!-- 左侧导航栏 -->
    <nav class="sidebar">
      <ul>
        <li
          v-for="category in categories"
          :key="category.id"
          :class="{ active: currentCategory === category.id }"
          @click="scrollToSection(category.id)"
        >
          {{ category.name }}
        </li>
      </ul>
    </nav>

    <!-- 右侧内容区 -->
    <main class="content">
      <section
        v-for="category in categories"
        :key="category.id"
        :id="'section-' + category.id"
        class="category-section"
      >
        <h2>{{ category.name }}</h2>
        <ul>
          <li v-for="item in category.items" :key="item.id">
            {{ item.name }}
          </li>
        </ul>
      </section>
    </main>
  </div>
</template>

2. Vue 脚本逻辑

<script>
import { ref, onMounted, onUnmounted } from "vue";
import { useRouter } from "vue-router";

export default {
  setup() {
    const categories = ref([
      { id: "image", name: "Image", items: ["Text to Image", "AI Avatar Generator"] },
      { id: "video", name: "Video", items: ["AI Animation", "Image to Video"] },
      // 添加更多分类
    ]);
    const currentCategory = ref(""); // 当前高亮分类
    const router = useRouter();

    // 滚动到指定分类
    const scrollToSection = (id) => {
      const target = document.getElementById(`section-${id}`);
      if (target) {
        target.scrollIntoView({ behavior: "smooth", block: "start" });
        currentCategory.value = id;
        router.push({ query: { group: id } }); // 更新路由
      }
    };

    // 滚动监听
    const handleScroll = () => {
      const sections = document.querySelectorAll(".category-section");
      let found = false;
      const offset = 100; // 偏移值,适应固定头部
      sections.forEach((section) => {
        const rect = section.getBoundingClientRect();
        if (!found && rect.top <= offset && rect.bottom > offset) {
          const id = section.id.replace("section-", "");
          if (currentCategory.value !== id) {
            currentCategory.value = id;
            router.replace({ query: { group: id } }); // 动态更新路由
          }
          found = true;
        }
      });
    };

    onMounted(() => {
      window.addEventListener("scroll", handleScroll);
    });

    onUnmounted(() => {
      window.removeEventListener("scroll", handleScroll);
    });

    return {
      categories,
      currentCategory,
      scrollToSection,
    };
  },
};
</script>

3. 样式设计

<style scoped>
.container {
  display: flex;
}
.sidebar {
  width: 200px;
  position: sticky;
  top: 0;
  background: #f8f8f8;
  padding: 20px;
}
.sidebar ul {
  list-style: none;
  padding: 0;
}
.sidebar li {
  cursor: pointer;
  padding: 10px;
  margin-bottom: 5px;
  border-radius: 5px;
  transition: background 0.3s;
}
.sidebar li.active {
  background: #d0e2ff;
  color: #000;
}
.sidebar li:hover {
  background: #e6f0ff;
}
.content {
  flex: 1;
  padding: 20px;
}
.category-section {
  margin-bottom: 50px;
}
.category-section h2 {
  margin-bottom: 20px;
  font-size: 24px;
}
</style>

4. 特性解释

  1. 滚动监听更新路由

    • handleScroll 函数监听滚动事件,根据当前滚动位置动态更新 currentCategory 和路由。
  2. 平滑滚动

    • 使用 scrollIntoView 实现点击导航后平滑滚动到对应区域。
  3. 高亮显示

    • 左侧导航栏通过 currentCategory 的值动态添加 active 样式。
  4. 路由支持

    • 使用 Vue Router 的 pushreplace 方法,在点击或滚动时更新地址栏中的 query 参数。

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
大前端打手
假程序员

评论(0)

添加评论