You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue 3 Composition API中实现滚动时导航栏类名的增删功能

Vue 3 Composition API 导航栏滚动类切换实现方案

实现核心逻辑

  • 监听页面滚动事件,实时获取当前页面垂直滚动距离
  • 设置滚动阈值,当滚动距离超过阈值时标记导航栏为滚动状态,回到阈值内时取消标记
  • 动态绑定class到导航栏元素,根据状态自动添加/移除scrolled类
  • 添加节流逻辑优化滚动事件触发频率,避免性能损耗
  • 组件卸载时移除滚动事件监听,防止内存泄漏

完整单文件组件实现示例

<template>
  <!-- 导航栏容器 -->
  <header :class="['site-navbar', isScrolled ? 'scrolled' : '']">
    <div class="navbar-content">
      <div class="logo">Graana Clone</div>
      <nav class="nav-menu">
        <a href="#" v-for="item in navItems" :key="item">{{ item }}</a>
      </nav>
    </div>
  </header>

  <!-- 页面其他内容 -->
  <main class="page-content">
    <!-- 填充足够内容使页面可滚动即可测试效果 -->
  </main>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

// 响应式状态:标记导航栏是否处于滚动状态
const isScrolled = ref(false)
// 滚动阈值,单位px,可根据设计需求调整
const SCROLL_THRESHOLD = 10

// 节流函数:控制滚动事件回调触发频率,默认200ms触发一次
const throttle = (func, delay = 200) => {
  let lastCall = 0
  return (...args) => {
    const now = Date.now()
    if (now - lastCall >= delay) {
      lastCall = now
      func.apply(this, args)
    }
  }
}

// 滚动事件处理逻辑
const handleScroll = throttle(() => {
  const scrollY = window.scrollY || document.documentElement.scrollTop
  isScrolled.value = scrollY > SCROLL_THRESHOLD
})

// 组件挂载时添加滚动监听
onMounted(() => {
  window.addEventListener('scroll', handleScroll, { passive: true })
})

// 组件卸载时移除滚动监听
onUnmounted(() => {
  window.removeEventListener('scroll', handleScroll)
})

// 示例导航菜单数据
const navItems = ['Buy', 'Rent', 'Sell', 'Projects', 'Agents', 'Guides']
</script>

<style scoped>
.site-navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  padding: 1.2rem 5%;
  transition: all 0.3s ease;
  z-index: 999;
  /* 默认未滚动状态样式 */
  background-color: transparent;
  color: #fff;
}

/* 滚动后添加的样式 */
.site-navbar.scrolled {
  background-color: #fff;
  color: #1a1a1a;
  box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08);
  padding: 0.8rem 5%;
}

.navbar-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 1400px;
  margin: 0 auto;
}

.nav-menu {
  display: flex;
  gap: 2rem;
}

.nav-menu a {
  text-decoration: none;
  color: inherit;
  font-weight: 500;
}

.page-content {
  margin-top: 80px;
  min-height: 200vh; /* 模拟长页面,方便测试滚动效果 */
}
</style>

可调整参数说明

  • 修改SCROLL_THRESHOLD的值可调整触发scrolled类的滚动高度
  • 修改节流函数的delay参数可调整滚动事件响应灵敏度,数值越低响应越快,性能消耗也越高
  • 样式部分可根据实际设计需求调整过渡效果、背景色、内边距等属性,和预期效果对齐

可选优化:抽离为可复用Composable

如果需要在多个组件复用滚动逻辑,可以把核心逻辑抽为自定义Hook:

// composables/useNavbarScroll.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useNavbarScroll(threshold = 10, throttleDelay = 200) {
  const isScrolled = ref(false)

  const throttle = (func, delay) => {
    let lastCall = 0
    return (...args) => {
      const now = Date.now()
      if (now - lastCall >= delay) {
        lastCall = now
        func.apply(this, args)
      }
    }
  }

  const handleScroll = throttle(() => {
    const scrollY = window.scrollY || document.documentElement.scrollTop
    isScrolled.value = scrollY > threshold
  }, throttleDelay)

  onMounted(() => {
    window.addEventListener('scroll', handleScroll, { passive: true })
  })

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

  return { isScrolled }
}

组件内直接引入使用即可:

import { useNavbarScroll } from '@/composables/useNavbarScroll'
const { isScrolled } = useNavbarScroll(10, 150)

内容的提问来源于stack exchange,提问作者Waseem Abbas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 07:57:00