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

在Nuxt.js中用Pinia实现导航hover自动加类及子菜单显隐

在Nuxt.js中用Pinia实现导航悬停显示子菜单

步骤1:完善Pinia Store

更新store.ts,添加跟踪激活导航项的状态和对应的action:

import { defineStore } from "pinia";
import { acceptHMRUpdate } from "pinia";

export const peymantecStore = defineStore({
  id: "peymantec-store",
  state: () => ({
    // 存储当前激活的导航项名称,null表示无激活项
    activeNav: null as string | null,
    activeSubmenuClass: "subMenuActive"
  }),

  actions: {
    // 设置激活的导航项
    setActiveNav(navName: string) {
      this.activeNav = navName;
    },
    // 清除激活的导航项
    clearActiveNav() {
      this.activeNav = null;
    }
  }
});

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(peymantecStore, import.meta.hot));
}

步骤2:修改Header.vue组件

引入Pinia Store,绑定鼠标事件到store的action,并根据激活状态显示对应子菜单:

<template>
  <header class="header container-fluid mx-auto my-auto">
    <!-- Extra menu links -->
    <nav class="extra-nav bg-blue-500 w-full h-10 flex mx-auto"></nav>
    <!-- navbar -->
    <nav class="main-nav container mx-auto my-auto">
      <ul class="mx-auto my-auto headerUl flex">
        <!-- logo -->
        <li>
          <NuxtLink to="/" class="mx-auto my-auto">
            <img
              class="w-32 h-auto cursor-pointer my-auto mx-auto"
              src="@/img/peymantec-logo-en.jpg"
              alt="Peymantec Logo"
            />
          </NuxtLink>
        </li>
        <!-- MainMenu -->
        <li
          :key="`navItem-${i}`"
          v-for="(n, i) in mainMenu"
          class="mx-auto my-auto relative"
          @mouseover="store.setActiveNav(n.name)"
          @mouseleave="store.clearActiveNav"
        >
          <NuxtLink
            :to="n.link"
            class="my-auto mx-auto w-1 py-3 headerLinks justify-between relative flex-row align-middle"
          >
            {{ n.name }}
            <!-- mainSvg -->
            <div class="inline-flex mx-1 my-auto align-middle">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="10"
                height="10"
                viewBox="0 0 30 30"
              >
                <path
                  d="M27.963 6.75 30 8.787l-1.018 1.018-12.964 12.963L15 23.787 1.018 9.805 0 8.787 2.037 6.75l1.018 1.018L15 19.713 26.945 7.768l1.018-1.018z"
                ></path>
              </svg>
            </div>
          </NuxtLink>
        </li>
      </ul>
    </nav>

    <!-- subMenus -->
    <!-- EngineeringsubMenus -->
    <nav
      class="container mx-auto my-auto w-full subMenu"
      :class="store.activeNav === 'مهندسی' ? store.activeSubmenuClass : ''"
      @mouseover="store.setActiveNav('مهندسی')"
      @mouseleave="store.clearActiveNav"
    >
      <div class="flex flex-auto">
        <!-- ServicesSub  -->
        <ul class="servicesSub p-2">
          <li class="mb-3">خدمات</li>
          <li
            :key="`navItem-${i}`"
            v-for="(n, i) in servicesSub"
            class="w-full mx-auto my-auto inline-flex px-3 py-3"
          >
            <NuxtLink :to="n.link">{{ n.name }}</NuxtLink>
          </li>
        </ul>
        <!-- ExpertiseSub -->
        <ul class="expertiseSub p-2">
          <li class="mb-3">تخصص</li>
          <li
            :key="`navItem-${i}`"
            v-for="(n, i) in expertiseSub"
            class="w-full mx-auto my-auto inline-flex px-3 py-3"
          >
            <NuxtLink :to="n.link">{{ n.name }}</NuxtLink>
          </li>
        </ul>
        <!-- HowWeWorkSub -->
        <ul class="howWeWorkSub p-2">
          <li class="mb-3">ما چطور کار میکنیم؟</li>
          <li
            :key="`navItem-${i}`"
            v-for="(n, i) in howWeWorkSub"
            class="w-full mx-auto my-auto inline-flex px-3 py-3"
          >
            <NuxtLink :to="n.link">{{ n.name }}</NuxtLink>
          </li>
        </ul>
      </div>
    </nav>

    <!-- 其他子菜单示例:比如"صنایع"的子菜单 -->
    <nav
      class="container mx-auto my-auto w-full subMenu"
      :class="store.activeNav === 'صنایع' ? store.activeSubmenuClass : ''"
      @mouseover="store.setActiveNav('صنایع')"
      @mouseleave="store.clearActiveNav"
    >
      <div class="p-4">
        <p>صنایع子菜单内容</p>
      </div>
    </nav>
  </header>
</template>

<script setup>
import { peymantecStore } from "@/store";
const store = peymantecStore();

// Main Menu
const mainMenu = [
  {
    name: "مهندسی",
    link: "/engineering",
    active: false,
  },
  {
    name: "صنایع",
    link: "/services",
    active: false,
  },
  {
    name: "درباره",
    link: "/about",
    active: false,
  },
  {
    name: "تماس",
    link: "/contact",
    active: false,
  },
];

// Engineering SubMenu
const servicesSub = [
  {
    name: "توسعه نرم افزار",
    link: "/development",
  },
  {
    name: "پردازش ابری",
    link: "/cloud",
  },
  {
    name: "اینترنت اشیا‌ و هوش مصنوعی",
    link: "/iot",
  },
  {
    name: "کسب و کار هوشمند",
    link: "/smart",
  },
];

const expertiseSub = [
  {
    name: "توسعه وب، موبایل و بلاک چین",
    link: "/services",
  },
  {
    name: "توسعه واقعیت افزوده و ان اف تی",
    link: "/about",
  },
  {
    name: "طراحی تجربه و رابط کاربری",
    link: "/about",
  },
  {
    name: "علم داه و کلان داده",
    link: "/about",
  },
];

const howWeWorkSub = [
  {
    name: "کشف نیازهای پروژه",
    link: "/services",
  },
  {
    name: "طراحی خلاقانه و توسعه هوشمند",
    link: "/about",
  },
  {
    name: "بررسی کیفیت و عملکرد محصول",
    link: "/about",
  },
  {
    name: "اجرا و تحویل نهایی  پروژه",
    link: "/about",
  },
];
</script>

<style lang="scss" scoped>
.header {
  position: relative;
  top: 0;
  left: 0;
  overflow: visible; /* 修改为visible,避免子菜单被截断 */
  display: flex;
  flex-direction: column;
}

.headerLinks {
  &:hover {
    color: #b48648;
    fill: #b48648;
  }
}

/* 子菜单默认隐藏 */
.subMenu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  background-color: white;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

/* 激活时显示子菜单 */
.subMenuActive {
  display: block;
}

.triangelActive {
  border-bottom: 1rem solid #b48648 !important;
}
</style>

关键修改说明

  1. Pinia状态管理:

    • 添加activeNav状态,存储当前悬停的导航项名称,用于匹配对应的子菜单
    • 新增setActiveNav和clearActiveNav两个action,分别用于设置和清除激活状态
  2. Header组件修改:

    • 引入并初始化Pinia Store
    • 给每个主导航项的<li>绑定@mouseover和@mouseleave事件,调用store的action更新状态
    • 子菜单通过:class绑定,根据store.activeNav的值判断是否添加激活类
    • 子菜单自身也绑定鼠标事件,避免鼠标移到子菜单上时触发隐藏
  3. CSS修正:

    • 修改.header的overflow为visible,防止子菜单被截断
    • 设置.subMenu默认display: none,激活时通过.subMenuActive改为display: block
    • 给子菜单添加绝对定位和阴影,提升视觉效果

扩展说明

如果需要给其他导航项(比如"صنایع")添加子菜单,只需复制现有的子菜单结构,修改:class的判断条件为对应的导航项名称即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:18:10