./index.vue 主文件
<template>
<div class="tree-menu">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'TreeMenu',
}
</script>
<style lang="scss">
.tree-menu {
width: 100%;
background-color: #000;
}
</style>
./MenuItem.vue 没子菜单的 menuitem
<template>
<div class="menu-item">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'MenuItem'
}
</script>
<style lang="scss" scoped>
.menu-item {
height: 50px;
text-align: center;
line-height: 50px;
}
</style>
./SubMenu.vue 二级菜单
<template>
<div class="sub-menu">
<!-- 标题和箭头 -->
<div class="title">
<slot name="title"></slot>
<span class="icon">></span>
</div>
<!-- ↓用户自己填充子菜单 -->
<div class="sub-item">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'SubMenu'
}
</script>
<style lang="scss" scoped>
.sub-menu {
position: relative;
.title {
position: relative;
height: 50px;
line-height: 50px;
text-align: center;
.icon {
position: absolute;
top: 0;
right: 15px;
}
}
.sub-item {
position: absolute;
top: 0;
left: 100%;
width: 100%;
background-color: #333;
}
}
</style>
<template>
<!-- 组件模板 -->
<div class="app">
<div class="side-bar">
<tree-menu>
<!-- 分成有子菜单和没有子菜单的 -->
<template
v-for="item of menuData"
>
<!-- 外边套一个template,避免v-if和v-for一起使用 -->
<!-- 没有子菜单的菜单 -->
<menu-item
v-if="!item.children"
:key="item.id"
>
{{ item.title }}
</menu-item>
<!-- 有子菜单的菜单 -->
<sub-menu
:key="item.id"
v-else
>
<template #title>{{ item.title }}</template>
<template
v-for="c of item.children"
>
<menu-item
:key="c.id"
>
{{ c.title }}
</menu-item>
</template>
</sub-menu>
</template>
</tree-menu>
</div>
</div>
</template>
<script>
import menuData from './data/menu';
// 组件逻辑 组件逻辑模块
export default {
name: 'App',
setup() {
return {
menuData
}
}
}
</script>
<style lang="scss" scoped>
.side-bar {
width: 300px;
color: #fff !important;
}
</style>
菜单数据:
export default [
{
id: 1,
title: '菜单1'
},
{
id: 2,
title: '菜单2'
},
{
id: 3,
title: '菜单3',
children: [
{
id: 31,
title: '菜单3-1',
},
{
id: 32,
title: '菜单3-2',
children: [
{
id: 321,
title: '菜单3-2-1',
},
{
id: 322,
title: '菜单3-2-2',
children: [
{
id: 3221,
title: '菜单3-2-2-1'
},
{
id: 3222,
title: '菜单3-2-2-2'
},
{
id: 3223,
title: '菜单3-2-2-3',
children: [
{
id: 32231,
title: '菜单3-2-2-3-1'
},
{
id: 32232,
title: '菜单3-2-2-3-2'
},
{
id: 32233,
title: '菜单3-2-2-3-3'
}
]
}
]
},
{
id: 323,
title: '菜单3-2-3',
}
]
},
{
id: 33,
title: '菜单3-3',
}
]
},
{
id: 4,
title: '菜单4'
},
{
id: 5,
title: '菜单5'
}
]
import App from './App.vue';
import TreeMenu from './components/TreeMenu/index.vue';
import MenuItem from './components/TreeMenu/MenuItem.vue';
import SubMenu from './components/TreeMenu/SubMenu.vue';
const app = Vue.createApp(App)
app.component('tree-menu', TreeMenu);
app.component('menu-item', MenuItem);
app.component('sub-menu', SubMenu);
app.mount('#app');
SubMenu.vue
<template>
<div class="sub-menu"
@mouseenter="showSubMenu"
@mouseleave="hideSubMenu"
>
<!-- 标题和箭头 -->
<div class="title">
<slot name="title"></slot>
<span class="icon">></span>
</div>
<!-- ↓用户自己填充子菜单 -->
<div class="sub-item" v-show="subMenuShow">
<slot></slot>
</div>
</div>
</template>
<script>
// Vue3 写法
import { ref } from 'vue';
export default {
name: 'SubMenu',
setup() {
const subMenuShow = ref(false);
const showSubMenu = () => {
subMenuShow.value = true;
}
const hideSubMenu = () => {
subMenuShow.value = false;
}
return {
subMenuShow,
showSubMenu,
hideSubMenu
}
}
}
</script>
<style lang="scss" scoped>
.sub-menu {
position: relative;
.title {
position: relative;
height: 50px;
line-height: 50px;
text-align: center;
.icon {
position: absolute;
top: 0;
right: 15px;
}
}
.sub-item {
position: absolute;
top: 0;
left: 100%;
width: 100%;
background-color: #333;
}
}
</style>