gcz 1 tydzień temu
rodzic
commit
525ddc41d7
1 zmienionych plików z 89 dodań i 19 usunięć
  1. 89 19
      src/components/layout/Header.vue

+ 89 - 19
src/components/layout/Header.vue

@@ -11,34 +11,41 @@
         </div>
 
         <!-- 导航菜单 -->
-        <nav class="nav">
+        <nav class="nav" ref="navRef">
           <ul class="nav-list">
             <li class="nav-item">
-              <router-link to="/" class="nav-link" :class="{ active: $route.path === '/' }">
+              <router-link to="/" class="nav-link" :class="{ active: $route.path === '/' }"
+                @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
                 首页
               </router-link>
             </li>
             <li class="nav-item">
-              <router-link to="/products" class="nav-link" :class="{ active: $route.path.startsWith('/products') }">
+              <router-link to="/products" class="nav-link" :class="{ active: $route.path.startsWith('/products') }"
+                @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
                 产品中心
               </router-link>
             </li>
             <li class="nav-item">
-              <router-link to="/cases" class="nav-link" :class="{ active: $route.path.startsWith('/cases') }">
+              <router-link to="/cases" class="nav-link" :class="{ active: $route.path.startsWith('/cases') }"
+                @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
                 行业案例
               </router-link>
             </li>
             <li class="nav-item">
-              <router-link to="/about" class="nav-link" :class="{ active: $route.path.startsWith('/about') }">
+              <router-link to="/about" class="nav-link" :class="{ active: $route.path.startsWith('/about') }"
+                @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
                 企业介绍
               </router-link>
             </li>
             <li class="nav-item">
-              <router-link to="/contact" class="nav-link" :class="{ active: $route.path.startsWith('/contact') }">
+              <router-link to="/contact" class="nav-link" :class="{ active: $route.path.startsWith('/contact') }"
+                @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
                 联系我们
               </router-link>
             </li>
           </ul>
+          <!-- 动态横线 -->
+          <div class="nav-indicator" ref="indicatorRef"></div>
         </nav>
 
         <!-- 移动端菜单按钮 -->
@@ -72,12 +79,16 @@
 </template>
 
 <script>
-import { ref } from 'vue'
+import { ref, onMounted, nextTick } from 'vue'
+import { useRoute } from 'vue-router'
 
 export default {
   name: 'Header',
   setup() {
     const mobileMenuOpen = ref(false)
+    const navRef = ref(null)
+    const indicatorRef = ref(null)
+    const route = useRoute()
 
     const toggleMobileMenu = () => {
       mobileMenuOpen.value = !mobileMenuOpen.value
@@ -87,10 +98,67 @@ export default {
       mobileMenuOpen.value = false
     }
 
+    // 设置横线位置
+    const setIndicatorPosition = (element) => {
+      if (!indicatorRef.value || !element) return
+
+      const rect = element.getBoundingClientRect()
+      const navRect = navRef.value.getBoundingClientRect()
+
+      // 计算相对于nav容器的位置
+      const left = rect.left - navRect.left
+      const width = rect.width * 0.6 // 横线宽度为文字宽度的60%
+      const centerOffset = (rect.width - width) / 2 // 居中偏移
+
+      indicatorRef.value.style.left = `${left + centerOffset}px`
+      indicatorRef.value.style.width = `${width}px`
+      indicatorRef.value.style.opacity = '1'
+    }
+
+    // 初始化横线位置到当前激活项
+    const initIndicator = () => {
+      nextTick(() => {
+        const activeLink = navRef.value?.querySelector('.nav-link.active')
+        if (activeLink) {
+          setIndicatorPosition(activeLink)
+        }
+      })
+    }
+
+    // 鼠标进入导航项
+    const handleMouseEnter = (event) => {
+      setIndicatorPosition(event.target)
+    }
+
+    // 鼠标离开导航项,回到激活项
+    const handleMouseLeave = () => {
+      const activeLink = navRef.value?.querySelector('.nav-link.active')
+      if (activeLink) {
+        setIndicatorPosition(activeLink)
+      } else {
+        // 如果没有激活项,隐藏横线
+        if (indicatorRef.value) {
+          indicatorRef.value.style.opacity = '0'
+        }
+      }
+    }
+
+    onMounted(() => {
+      initIndicator()
+      // 监听路由变化,重新设置横线位置
+      nextTick(() => {
+        initIndicator()
+      })
+    })
+
     return {
       mobileMenuOpen,
+      navRef,
+      indicatorRef,
       toggleMobileMenu,
-      closeMobileMenu
+      closeMobileMenu,
+      handleMouseEnter,
+      handleMouseLeave
     }
   }
 }
@@ -136,6 +204,8 @@ export default {
 }
 
 .nav {
+  position: relative;
+
   .nav-list {
     display: flex;
     align-items: center;
@@ -148,7 +218,7 @@ export default {
     color: $text-primary;
     padding: 8px 0;
     position: relative;
-    transition: all 0.3s ease;
+    transition: color 0.3s ease;
     display: block;
     height: 100px;
     line-height: 100px;
@@ -157,17 +227,17 @@ export default {
     &.active {
       color: $primary-color;
     }
+  }
 
-    &.active::after {
-      content: '';
-      position: absolute;
-      bottom: -0;
-      left: 0;
-      right: 0;
-      height: 2px;
-      background: $primary-color;
-      border-radius: 1px;
-    }
+  .nav-indicator {
+    position: absolute;
+    bottom: 0;
+    height: 2px;
+    background: $primary-color;
+    border-radius: 1px;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    opacity: 0;
+    pointer-events: none;
   }
 }