|
@@ -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;
|
|
|
}
|
|
|
}
|
|
|
|