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

如何在Vue 3中使用Composition API实现滚动时隐藏导航栏

解决Vue3 Composition API实现滚动显示/隐藏导航栏的问题

原生JS实现代码:

let prevScrollpos = window.pageYOffset;
window.onscroll = function () {
  console.log('scrolling')
  let currentScrollPos = window.pageYOffset;
  if (prevScrollpos > currentScrollPos) {
    // @ts-ignore
    document.getElementById("navbar").style.top = "0";
  } else {
    // @ts-ignore
    document.getElementById("navbar").style.top = "-65px";
  }
  prevScrollpos = currentScrollPos;
}

下面提供三种适配Vue3 Composition API的解决方案:

一、在Navbar.vue组件内实现(推荐)

直接在导航组件内部监听滚动事件,结合Vue的响应式和生命周期钩子管理监听:

<template>
  <nav ref="navbarRef" class="navbar">
    <!-- 导航内容 -->
  </nav>
</template>

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

const navbarRef = ref(null)
let prevScrollpos = window.pageYOffset

const handleScroll = () => {
  const currentScrollPos = window.pageYOffset
  if (navbarRef.value) {
    navbarRef.value.style.top = prevScrollpos > currentScrollPos ? '0' : '-65px'
  }
  prevScrollpos = currentScrollPos
}

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

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

<style scoped>
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 65px;
  transition: top 0.3s ease; /* 加上过渡动画更流畅 */
}
</style>

说明:

  • 用ref获取导航栏DOM元素,避免直接通过getElementById操作DOM,更符合Vue的规范
  • 在onMounted中注册滚动监听,onUnmounted中移除,防止内存泄漏
  • 添加过渡动画让显示/隐藏更平滑

二、自定义指令方案

如果需要在多个组件复用该功能,可以封装成自定义指令:

1. 全局注册指令(main.js)

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.directive('scroll-navbar', {
  mounted(el) {
    let prevScrollpos = window.pageYOffset
    const handleScroll = () => {
      const currentScrollPos = window.pageYOffset
      el.style.top = prevScrollpos > currentScrollPos ? '0' : '-65px'
      prevScrollpos = currentScrollPos
    }
    window.addEventListener('scroll', handleScroll)
    // 监听组件卸载,移除事件监听
    el._scrollHandler = handleScroll
  },
  unmounted(el) {
    window.removeEventListener('scroll', el._scrollHandler)
  }
})

app.mount('#app')

2. 在组件中使用

<template>
  <nav v-scroll-navbar class="navbar">
    <!-- 导航内容 -->
  </nav>
</template>

<style scoped>
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 65px;
  transition: top 0.3s ease;
}
</style>

三、在App.vue中全局监听

如果需要统一管理滚动逻辑,也可以在根组件中实现:

<template>
  <div id="app">
    <nav ref="navbarRef" class="navbar">
      <!-- 导航内容 -->
    </nav>
    <router-view />
  </div>
</template>

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

const navbarRef = ref(null)
let prevScrollpos = window.pageYOffset

const handleScroll = () => {
  const currentScrollPos = window.pageYOffset
  if (navbarRef.value) {
    navbarRef.value.style.top = prevScrollpos > currentScrollPos ? '0' : '-65px'
  }
  prevScrollpos = currentScrollPos
}

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

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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 01:06:17