140 lines
3.0 KiB
Vue
140 lines
3.0 KiB
Vue
<template>
|
||
<div class="menu-container">
|
||
|
||
<!-- 一级导航 -->
|
||
<div class="menu-level-1">
|
||
<div
|
||
v-for="item in level1"
|
||
:key="item.id"
|
||
class="menu-item"
|
||
:class="{ active: selectedParentId === item.id }"
|
||
@click="selectParent(item)"
|
||
>
|
||
{{ item.name }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 二级导航区域 -->
|
||
<transition name="fade">
|
||
<div
|
||
v-if="childList.length"
|
||
class="menu-level-2"
|
||
:style="{ gridRowStart: childRowIndex }"
|
||
>
|
||
<div
|
||
v-for="child in childList"
|
||
:key="child.id"
|
||
class="menu-item child"
|
||
>
|
||
{{ child.name }}
|
||
</div>
|
||
</div>
|
||
</transition>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from "vue"
|
||
|
||
// 模拟接口返回的一级导航
|
||
const level1 = ref([
|
||
{ id: 1, name: "导航1", children: [] },
|
||
{ id: 2, name: "导航2", children: [
|
||
{ id: 21, name: "子2-1" },
|
||
{ id: 22, name: "子2-2" },
|
||
{ id: 23, name: "子2-3" }
|
||
]},
|
||
{ id: 3, name: "导航3", children: [] },
|
||
{ id: 4, name: "导航4", children: [
|
||
{ id: 41, name: "子4-1" },
|
||
{ id: 42, name: "子4-2" }
|
||
]},
|
||
{ id: 5, name: "导航5", children: [] },
|
||
{ id: 6, name: "导航6", children: [
|
||
{ id: 61, name: "子6-1" },
|
||
{ id: 62, name: "子6-2" },
|
||
{ id: 63, name: "子6-3" },
|
||
{ id: 64, name: "子6-4" },
|
||
]},
|
||
{ id: 7, name: "导航7", children: [] },
|
||
{ id: 8, name: "导航8", children: [] }
|
||
])
|
||
|
||
// 选择的一级导航
|
||
const selectedParentId = ref(null)
|
||
|
||
// 当前一级导航的子级
|
||
const childList = computed(() => {
|
||
const parent = level1.value.find(i => i.id === selectedParentId.value)
|
||
return parent ? parent.children : []
|
||
})
|
||
|
||
// 计算二级导航应该显示在哪一行(每行 4 个)
|
||
const childRowIndex = computed(() => {
|
||
if (!selectedParentId.value) return 3
|
||
const index = level1.value.findIndex(i => i.id === selectedParentId.value)
|
||
return Math.floor(index / 4) + 2 // 第一行 row=1,二级导航从 row=2 或 row=3
|
||
})
|
||
|
||
const selectParent = (item) => {
|
||
// 点击同一个时关闭
|
||
if (selectedParentId.value === item.id) {
|
||
selectedParentId.value = null
|
||
} else {
|
||
selectedParentId.value = item.id
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.menu-container {
|
||
display: grid;
|
||
grid-template-rows: auto auto auto;
|
||
gap: 10px;
|
||
}
|
||
|
||
/* 一级导航:4列布局 */
|
||
.menu-level-1 {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 10px;
|
||
}
|
||
|
||
.menu-item {
|
||
padding: 12px;
|
||
text-align: center;
|
||
background: #4a90e2;
|
||
color: white;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.menu-item.active {
|
||
background: #2d73c7;
|
||
}
|
||
|
||
/* 二级导航:自动换行 */
|
||
.menu-level-2 {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 8px;
|
||
background: #2d73c7;
|
||
padding: 10px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.menu-item.child {
|
||
background: #1e4f8a;
|
||
}
|
||
|
||
/* 动画 */
|
||
.fade-enter-active, .fade-leave-active {
|
||
transition: all .2s ease;
|
||
}
|
||
.fade-enter-from, .fade-leave-to {
|
||
opacity: 0;
|
||
transform: translateY(-5px);
|
||
}
|
||
</style>
|