样式如上
需要typescript,vue3环境下运行
需要下载依赖如下
npm install sass-loader node-sass --save-dev
npm install element-plus --save
npm install view-ui-plus@1.3.1 --save
main.ts中
import 'view-ui-plus/dist/styles/viewuiplus.css'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
需要scss以及,element-plus
<template>
<div class="sidebar">
<el-menu :default-active="activeIndex" class="menu" active-text-color="#FFFFFF" background-color="#060E83"
text-color="#fff" :unique-opened="true" router @select="handleSelect" @close="menuClose" @open="menuOpen">
<template v-for="menus in ItemList" :key="menus">
<el-sub-menu :key="menus.menuId" :index="menus.index" v-if="menus.childs">
<template #title>
<img :src="menus.icon" alt="" style="margin-right: 16px;width: 22px;height: 22px;">
<span>{{ menus.title }}</span>
</template>
<el-timeline style="box-sizing: border-box;padding-left: 20px;">
<el-timeline-item v-for="(childvl, ci) in menus.childs" :key="ci" center @click="changeColor">
<!-- {{ activity.content }} -->
<el-menu-item :index="childvl.index" :key="ci" style="margin-bottom:10px;">{{
childvl.title
}}</el-menu-item>
</el-timeline-item>
</el-timeline>
</el-sub-menu>
<el-menu-item :index="menus.index" v-else style="margin-bottom:10px;">
<img :src="menus.icon" alt="" style="margin-right: 16px;">
<span>{{ menus.title }}</span>
</el-menu-item>
</template>
</el-menu>
</div>
</template>
<script lang="ts" setup>
import getData from "@/assets/json/st_classlist.json";
import { ref, onMounted } from "vue";
const ItemList: any = ref([])
const activeIndex = ref('')
const handleSelect = (key: any) => {
activeIndex.value = key
}
function addRouterIndex() {
setTimeout(() => {
const childrenArray = ItemList.value.map((item: any) => {
return item.childs;
});
//用来存放child里不为null的值
let intChild = []
intChild = childrenArray.filter(function (val: any) {
return val
});
//把intChild中的所有数组拼接起来
const flattenedArray = intChild.reduce((acc: any[], cur: any) => {
return acc.concat(cur);
}, []);
//获取该路由所对应的下标
const index = flattenedArray.findIndex((person: { index: string; }) => person.index === activeIndex.value);
let nodes = document.querySelectorAll('.el-timeline-item__node')[index] as HTMLElement
if (nodes) {
nodes.style.background = "#fff"
nodes.style.transition = "0.5s"
}
}, 100);
}
const popstate = () => {
activeIndex.value = location.hash.split("/")[1]
addRouterIndex()
}
const changeColor = () => {
addRouterIndex()
}
const menuClose = () => {
addRouterIndex()
}
const menuOpen = () => {
addRouterIndex()
}
onMounted(() => {
// console.log(getData.data);
ItemList.value = getData.data
popstate()
window.addEventListener('popstate', popstate, false);
addRouterIndex()
console.log(ItemList.value);
})
</script>
<style scoped lang="scss">
.sidebar {
height: calc(100vh - 76px);
box-shadow: 2px 0px 6px 0px rgba(0, 0, 0, 0.1);
.menu {
border-right: unset;
height: 100%;
width: 240px;
font-size: 16px;
.el-sub-menu {
width: 224px;
height: auto;
border-radius: 8px;
margin: auto;
}
::v-deep .el-sub-menu__title {
font-size: 16px;
}
.el-menu-item {
// width: 224px;
height: 50px;
border-radius: 8px;
margin: auto;
font-size: 16px;
}
.is-active {
background: rgba(94, 103, 246, 0.3);
}
.logo {
height: 50px;
line-height: 50px;
padding: 0 10px;
overflow: hidden;
img {
vertical-align: middle;
margin-left: 6px;
}
span {
font-weight: bold;
font-size: 16px;
}
}
}
.menu:not(.el-menu--collapse) {
width: 240px;
}
}
::v-deep .el-sub-menu .el-menu-item {
min-width: 0;
}
::v-deep .el-timeline-item__wrapper {
top: 0px !important;
height: 49px;
}
::v-deep .el-timeline-item__node {
background: #2B329A;
}
.el-timeline {
--el-timeline-node-color: #2B329A;
}
.el-active-fff {
background: #fff;
}
::v-deep .el-timeline-item__wrapper {
height: 40px;
}
.sidebar .menu[data-v-0f7446ba]:not(.el-menu--collapse) {
box-sizing: border-box;
padding-top: 20px;
}
</style>
下面是JSON文件内容
{
"code": 200,
"message": "操作成功",
"data": [
{
"index": "ceshione",
"icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
"title": "测试",
"menuId": "1082",
"component": null,
"childs": [
{
"index": "ceshitwo",
"icon": "#",
"title": "测试",
"menuId": "1087",
"component": null,
"childs": null
},
{
"index": "ceshithree",
"icon": "#",
"title": "测试",
"menuId": "1088",
"component": null,
"childs": null
}
]
},
{
"index": "ceshifore",
"icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
"title": "测试",
"menuId": "1083",
"component": null,
"childs": [
{
"index": "ceshifive",
"icon": "#",
"title": "测试",
"menuId": "1089",
"component": null,
"childs": null
}
]
},
{
"index": "",
"icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
"title": "测试",
"menuId": "1084",
"component": null,
"childs": [
{
"index": "ceshisix",
"icon": "#",
"title": "测试",
"menuId": "1001",
"component": null,
"childs": null
}
]
},
{
"index": "#",
"icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
"title": "测试",
"menuId": "1086",
"component": null,
"childs": [
{
"index": "ceshieight",
"icon": "#",
"title": "测试",
"menuId": "1089",
"component": null,
"childs": null
}
]
}
]
}