Nuxt 3中UNavigationMenu组件页面重载时无法高亮哈希对应导航项的问题咨询
我最近在Nuxt 3项目里用Nuxt UI的<UNavigationMenu>做页面内的锚点导航,点击菜单能正常滚动到#about、#products这些区块,当前项的高亮也没问题,但遇到一个头疼的问题:刷新页面的时候,比如当前页面地址是/#products,页面确实会自动滚动到products区块,但导航菜单始终高亮第一个“Home”项,完全不识别当前的hash路径。有没有办法让组件在页面加载时自动读取当前路由的hash,把对应的导航项设为激活状态?
先贴一下我现在的components/AppHeader.vue代码:
<template> <header class="bg-white sticky top-0 z-50"> <nav class="lg:flex flex-1 justify-center"> <UNavigationMenu v-model="activeSection" :items="navItems" class="space-x-2" highlight highlight-color="primary" > <template #item="{ item, active }"> <ULink as-child :to="{ path: '', hash: `#${item.to}` }" exact-hash class="px-4 py-2 rounded-md transition" aria-label="Go to {{ item.label }}" > <span class="inline-flex items-center"> <UIcon v-if="item.icon" :name="item.icon" class="size-5 mr-2" /> <span>{{ item.label }}</span> </span> </ULink> </template> </UNavigationMenu> </nav> </header> </template> <script setup lang="ts"> import { ref, watch, onMounted } from "vue"; import { useRoute } from "vue-router"; import type { NavigationMenuItem } from "@nuxt/ui"; const route = useRoute(); // Define your nav data (to = hash without leading '#') const navItems = ref<NavigationMenuItem[]>([ { label: "Home", icon: "i-lucide-home", value: "", to: "" }, { label: "About Us", icon: "i-lucide-user-circle", value: "about", to: "about" }, { label: "Products", icon: "i-lucide-package", value: "products", to: "products" }, { label: "Technologies", icon: "i-lucide-cpu", value: "technologies", to: "technologies" }, { label: "News", icon: "i-lucide-newspaper", value: "news", to: "news" }, ]); </script>
解决思路和修改方案
问题的核心是:<UNavigationMenu>的v-model绑定的activeSection默认没有根据当前路由的hash初始化,页面刷新时组件只会用初始值(也就是Home对应的'')来高亮,不会自动读取路由状态。我们需要手动同步路由hash和activeSection的值:
- 初始化
activeSection时读取当前路由的hash - 监听路由hash的变化,实时更新
activeSection
修改后的<script setup>部分如下:
import { ref, watch, onMounted } from "vue"; import { useRoute } from "vue-router"; import type { NavigationMenuItem } from "@nuxt/ui"; const route = useRoute(); // 初始化activeSection:从路由hash提取(去掉开头的#),如果hash为空则用''对应Home const activeSection = ref(route.hash.slice(1) || ''); // Define your nav data (to = hash without leading '#') const navItems = ref<NavigationMenuItem[]>([ { label: "Home", icon: "i-lucide-home", value: "", to: "" }, { label: "About Us", icon: "i-lucide-user-circle", value: "about", to: "about" }, { label: "Products", icon: "i-lucide-package", value: "products", to: "products" }, { label: "Technologies", icon: "i-lucide-cpu", value: "technologies", to: "technologies" }, { label: "News", icon: "i-lucide-newspaper", value: "news", to: "news" }, ]); // 监听路由hash变化,同步更新activeSection watch( () => route.hash, (newHash) => { activeSection.value = newHash.slice(1) || ''; }, { immediate: true } // 确保监听一开始就执行一次 ); // 额外在onMounted里再检查一次,避免路由解析延迟导致的问题 onMounted(() => { activeSection.value = route.hash.slice(1) || ''; });
为什么这样有效?
- 初始化时直接从
route.hash提取对应的导航项value(比如#products提取成products),这样页面刷新时一开始就能把正确的项设为激活状态。 - 监听
route.hash的变化,不管是刷新页面、手动修改地址栏hash,还是通过其他方式改变hash,都能同步更新导航的激活状态。 onMounted的额外检查是为了处理路由可能在组件挂载后才完全解析的边缘情况,确保万无一失。
现在刷新页面或者直接访问带hash的地址,导航菜单就能正确高亮对应的项了!
内容来源于stack exchange
相关产品推荐
相关产品推荐

