321 lines
7.9 KiB
Vue
321 lines
7.9 KiB
Vue
<template>
|
|
<div class="menu-bar" v-click-outside="clickOutside">
|
|
<div class="menu-bar-item" v-for="(item, i) in menus" :key="i">
|
|
<div class="menu-bar-no-child">
|
|
<!-- <img
|
|
class="menu-bar-item-img"
|
|
:style="{
|
|
opacity: item.check && item.children.length === 0 ? 1 : 0,
|
|
}"
|
|
src="../assets/img/down_circle.png"
|
|
/> -->
|
|
<div
|
|
class="menu-bar-item-main"
|
|
:class="{ 'menu-bar-item-main-active': item.check || index == i }"
|
|
@click="parentCheck($event, item, i)"
|
|
>
|
|
<div class="menu-bar-item-main-icon">
|
|
<i class="iconfont" v-html="item.icon"></i>
|
|
</div>
|
|
<div class="menu-bar-item-main-text">
|
|
<div>{{ item[property] }}</div>
|
|
<i
|
|
v-if="item.children.length > 0"
|
|
class="iconfont"
|
|
:class="{ 'iconfont-active': item.unfold }"
|
|
></i
|
|
>
|
|
</div>
|
|
</div>
|
|
<!-- <img
|
|
class="menu-bar-item-img"
|
|
:style="{
|
|
opacity: item.check && item.children.length === 0 ? 1 : 0,
|
|
}"
|
|
src="../assets/img/up_circle.png"
|
|
/> -->
|
|
</div>
|
|
<div class="menu-bar-has-child">
|
|
<div
|
|
class="menu-bar-item-child"
|
|
v-for="(child, childIndex) in item.children"
|
|
:key="childIndex"
|
|
>
|
|
<div class="menu-bar-item-parent">
|
|
<div
|
|
class="menu-bar-item-main"
|
|
:style="{
|
|
background: child.check ? 'rgba(112, 185, 54, 0.1)' : '#ffffff',
|
|
color: child.check ? '#70b936' : '#000000',
|
|
height: '32px',
|
|
margin: '10px 0',
|
|
borderRadius: '0',
|
|
}"
|
|
@click="childCheck(child, i)"
|
|
>
|
|
<div class="menu-bar-item-main-icon">
|
|
<i class="iconfont" v-html="child.icon"></i>
|
|
</div>
|
|
<div class="menu-bar-item-main-text">{{ child[property] }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, watch } from "@vue/runtime-core";
|
|
import { useRoute } from "vue-router";
|
|
export default {
|
|
name: "LeftMenuBar",
|
|
props: {
|
|
list: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
property: {
|
|
type: String,
|
|
default: "name",
|
|
},
|
|
},
|
|
activated() {
|
|
const route = useRoute();
|
|
const path = route.path;
|
|
this.menus.forEach((x) => {
|
|
x.check = x.path === path;
|
|
});
|
|
},
|
|
setup(props, context) {
|
|
const index = ref(null);
|
|
const route = useRoute();
|
|
let menus = props.list.map((first) => {
|
|
const path = route.path;
|
|
first.check = path === first.path;
|
|
first.unfold = false;
|
|
first.children = first.children.map((second) => {
|
|
second.check = false;
|
|
return second;
|
|
});
|
|
return first;
|
|
});
|
|
const { parentCheck, childCheck, clickOutside } = domHandle(menus, context);
|
|
watch(
|
|
() => route.path,
|
|
() => {
|
|
console.log("menus", menus);
|
|
menus = menus.map((first) => {
|
|
const path = route.path;
|
|
first.check = path === first.path;
|
|
// first.unfold = false;
|
|
// first.children = first.children.map((second) => {
|
|
// second.check = false;
|
|
// return second;
|
|
// });
|
|
return first;
|
|
});
|
|
}
|
|
);
|
|
// 点击一级菜单名称
|
|
const menuName = ref("");
|
|
function domHandle(menus, context) {
|
|
// 点击一级菜单
|
|
const parentCheck = (e, item, i) => {
|
|
if (menuName.value !== item.name) {
|
|
menusStatusToFalsefather(menus);
|
|
}
|
|
menuName.value = item.name;
|
|
if (item.disable) return;
|
|
if (item.children.length > 0) {
|
|
item.unfold = !item.unfold;
|
|
const $checkDom = e.currentTarget.parentElement.nextElementSibling;
|
|
$checkDom.style.height = item.unfold
|
|
? `${$checkDom.scrollHeight}px`
|
|
: 0;
|
|
$checkDom.style.borderRadius = item.unfold || 0;
|
|
return;
|
|
}
|
|
if (item.check) return;
|
|
menusStatusToFalse(menus);
|
|
item.check = true;
|
|
index.value = i;
|
|
context.emit("menuCheck", item);
|
|
};
|
|
// 点击二级菜单
|
|
const childCheck = (child, i) => {
|
|
if (!!child.check) return;
|
|
menusStatusToFalse(menus);
|
|
context.emit("menuCheck", child);
|
|
child.check = true;
|
|
index.value = i;
|
|
menusStatusToFalsefather(menus);
|
|
};
|
|
const clickOutside = () => {
|
|
menus.forEach((x) => {
|
|
if (x.children && x.unfold) {
|
|
x.unfold = false;
|
|
const menuChild$ = document.querySelectorAll(".menu-bar-has-child");
|
|
for (let index = 0; index < menuChild$.length; index++) {
|
|
const element = menuChild$[index];
|
|
element.style.height = 0;
|
|
}
|
|
}
|
|
});
|
|
};
|
|
return {
|
|
parentCheck,
|
|
childCheck,
|
|
clickOutside,
|
|
};
|
|
}
|
|
return {
|
|
menus,
|
|
index,
|
|
parentCheck,
|
|
childCheck,
|
|
clickOutside,
|
|
};
|
|
},
|
|
};
|
|
|
|
function menusStatusToFalse(menus) {
|
|
menus.forEach((x) => {
|
|
x.check = false;
|
|
if (x.children) {
|
|
menusStatusToFalse(x.children);
|
|
}
|
|
});
|
|
}
|
|
function menusStatusToFalsefather(menus) {
|
|
menus.forEach((x) => {
|
|
x.unfold = false;
|
|
var menubar = document.getElementsByClassName("menu-bar-has-child");
|
|
for (var key = 0; key < menubar.length; key++) {
|
|
menubar[key].style.height = "0px";
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.menu-bar {
|
|
display: flex;
|
|
width: 100%;
|
|
height: 48px;
|
|
font-size: 13px;
|
|
z-index: 99999;
|
|
&-item {
|
|
position: relative;
|
|
width: 220px;
|
|
z-index: 99;
|
|
background: rgba(245, 245, 245, 0.6);
|
|
&-child {
|
|
background-color: #ffffff;
|
|
.menu-bar-item-main-text{
|
|
width: 68px;
|
|
}
|
|
}
|
|
&-img {
|
|
width: 10px;
|
|
height: 10px;
|
|
line-height: 50px;
|
|
display: block;
|
|
margin-left: 61px;
|
|
transition: all 0.3s;
|
|
}
|
|
&-main {
|
|
width: 220px;
|
|
height: 48px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 8px 8px 0px 0px;
|
|
padding-right: 5px;
|
|
transition: all 0.3s;
|
|
&-active {
|
|
color: $yili-default-color;
|
|
background: #ffffff;
|
|
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
|
}
|
|
&-icon {
|
|
opacity: 0.9;
|
|
margin: 8px 10px 0 0;
|
|
}
|
|
&-text {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-top: 8px;
|
|
opacity: 0.8;
|
|
div {
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
.iconfont {
|
|
font-size: 20px;
|
|
height: 18px;
|
|
line-height: 20px;
|
|
transition: all 0.3s;
|
|
transform: rotate(0deg);
|
|
}
|
|
.iconfont-active {
|
|
transform: rotate(180deg);
|
|
}
|
|
&:hover &-icon {
|
|
opacity: 1;
|
|
}
|
|
&:hover &-text {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
&-no-child {
|
|
}
|
|
&-has-child {
|
|
overflow: hidden;
|
|
transition: all 0.3s;
|
|
height: 0;
|
|
border-radius: 5px 5px 5px 5px;
|
|
box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 10%);
|
|
}
|
|
.menu-bar-item:last-child {
|
|
border-radius: 0px 8px 0px 0px;
|
|
}
|
|
.menu-bar-item:first-child {
|
|
border-radius: 8px 0px 0px 0px;
|
|
}
|
|
}
|
|
.menu-bar-item-main-text {
|
|
font-size: 0.75rem;
|
|
z-index: 99;
|
|
}
|
|
.menu-bar-item-main-icon {
|
|
z-index: 99;
|
|
}
|
|
::v-deep(.menu-bar-item-main) {
|
|
position: relative;
|
|
z-index: 99;
|
|
}
|
|
.menu-bar-item-child {
|
|
height: 50px;
|
|
display: block;
|
|
position: relative;
|
|
top: 0;
|
|
left: 0;
|
|
/* background: #ffffff; */
|
|
z-index: 999;
|
|
}
|
|
.menu-bar-item-parent {
|
|
height: 50px;
|
|
position: absolute;
|
|
z-index: 999;
|
|
left: 0;
|
|
top: 0;
|
|
background: #ffffff;
|
|
opacity: 1;
|
|
z-index: 100;
|
|
height: 50px;
|
|
}
|
|
</style>
|