1、背景:
由于之前,做小程序的时候,需要用到树状菜单显示,但是又没有原生小程序好像是没有相关组件的,当时是网上找了一个组件暂时使用着,现在想起了,觉得有必要自己写一下,于是就开始尝试一下
2、效果
3、代码
app.vue代码
<template>
<div class="app">
<div class="app-menu">
<TreeMenu :data="state.data" :depth="0" :active-ids="['1']" />
</div>
</div>
</template>
<script setup lang="ts">
import { reactive } from "vue";
import TreeMenu from "./components/TreeMenu.vue";
const state = reactive({
data: [
{
id: "1",
title: "菜单1",
children: [
{
id: "1-1",
title: "菜单1-1",
children: [
{ id: "1-1-1", title: "菜单1-1-1" },
{ id: "1-1-2", title: "菜单1-1-2" },
{ id: "1-1-3", title: "菜单1-1-3" },
],
},
{ id: "1-2", title: "菜单1-2" },
{ id: "1-3", title: "菜单1-3" },
],
},
{
id: "2",
title: "菜单2",
children: [
{
id: "2-1",
title: "菜单2-1",
children: [
{ id: "2-1-1", title: "菜单2-1-1" },
{ id: "2-1-2", title: "菜单2-1-2" },
{ id: "2-1-3", title: "菜单2-1-3" },
],
},
{ id: "2-2", title: "菜单2-2", children: [] },
{ id: "2-3", title: "菜单2-3" },
],
},
{
id: "3",
title: "菜单3",
children: [
{
id: "3-1",
title: "菜单3-1",
children: [
{ id: "3-1-1", title: "菜单3-1-1" },
{ id: "3-1-2", title: "菜单3-1-2" },
{ id: "3-1-3", title: "菜单3-1-3" },
],
},
{ id: "3-2", title: "菜单3-2" },
{ id: "3-3", title: "菜单3-3" },
],
},
],
});
</script>
<style scoped lang="scss">
.app-menu {
width: 200px;
min-height: 500px;
background: #f4f4f4;
}
</style>
菜单组件代码
<template>
<div class="menu">
<div class="menu-container" v-for="item in state.data" :key="item.id">
<!-- 显示的标题 -->
<div
class="title"
:class="{ active: state.activeIds[props.depth] === item.id }"
@click="activeEvent(item.id)"
>
{{ item.title }}
</div>
<!-- children属性存在才渲染 -->
<template v-if="item.children?.length > 0">
<!-- 激活项是当前项才显示其子菜单 -->
<TreeMenu
:data="item.children"
v-show="state.activeId === item.id"
:active-ids="state.activeIds"
:depth="props.depth + 1"
/>
</template>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive } from "vue";
import TreeMenu from "@/components/TreeMenu.vue";
// 接收父组件传过来的数据
const props = defineProps<{
data: any;
activeIds: Array<string>;
depth: number;
}>();
// 将数据保存到本地
const state = reactive({
data: props.data,
activeId: "",
activeIds: props.activeIds,
});
// 激活项改变
const activeEvent = (val: string) => {
state.activeId = val;
// 修改对应层级的激活id
state.activeIds[props.depth] = val;
// 把当前层级的下一级的激活id去掉,不然当前层级改变后,在返回改变之前的id,其子层级激活的id还在
state.activeIds.forEach((item, index, arr) => {
if (index > props.depth) {
arr[index] = "";
}
});
console.log(state.activeIds);
};
</script>
<style scoped lang="scss">
.menu {
width: 200px;
overflow: hidden;
background: #f4f4f4;
color: #333;
.menu-container {
width: 100%;
padding-left: 10px;
box-sizing: border-box;
.title {
padding-left: 10px;
box-sizing: border-box;
height: 40px;
line-height: 40px;
&:hover {
cursor: pointer;
background: rgba(0, 0, 0, 0.8);
color: #fff;
}
}
.active {
color: #e4393c !important;
}
}
}
</style>
初次尝试写的递归组件,欢迎指教!!