实现效果
用途:一般用于后台管理系统的导航菜单,附源码,有兴趣的朋友可以参考自行修改。
涉及到知识点:
1、flex布局,用好flex,能够解决布局的大部分问题
2、鼠标经过改变子元素样式
3、鼠标经过改变父元素样式
4、动态修改class
5、css画三角形
6、数组数据过滤
整理一下 flex 常用的样式类,了解更多可以查看源码 src/assets/css/base.css
/* flex布局 */
.flex {
display: flex;
}
/* 竖向排列 */
.flex-col {
flex-direction: column;
}
/* 横向排列 */
.flex-row {
flex-direction: row;
}
/* 水平居中 */
.flex-center-sp {
justify-content: center;
}
/* 垂直居中 */
.flex-center-cz {
align-items: center;
}
/* 两端靠边 */
.flex-space-between {
justify-content: space-between;
}
/* 平均分布空间 */
.flex-space-evenly {
justify-content: space-evenly;
}
鼠标经过改变子元素样式,了解更多可以查看源码 src/assets/css/ui.css
/* 经过主菜单时左边亮块 */
.ui-menu .item :hover .left {
display: block;
background-color: #3dc886;
width: 4px;
height: 100%;
}
/* 经过主菜单时文字显示 */
.ui-menu .item .master:hover .text {
color: #fff;
}
鼠标经过改变父元素样式, hover 无法实现了,要用到 @mouseover(鼠标经过事件) @mouseout(鼠标离开事件)
……
<div class="lh detail flex pointer cannotselect" :class="{'active': activeDetailItemId==detail.id}"
@click="dClick(detail)" @mouseover="mouseover(item.id)" @mouseout="mouseout()">
<div class="text">{
{detail.name}}</div>
</div>
……
data() {
return {
activeMasterItemId : null,
activeDetailItemId: null
}
},
methods:{
mouseover(mid) {
this.activeMasterItemId = mid
},
mouseout() {
this.activeMasterItemId = 0
},
……
}
动态修改class,此处的activeMasterItemId是子元素鼠标经过后进行的赋值,父元素根据此值来显示样式
……
<div class="left margin-right-l" :class="{'active': activeMasterItemId==item.id}" ></div>
<div class="text" :class="{'active-text': activeMasterItemId==item.id}" >{
{item.name}}</div>
css画三角形
/* 倒三角 */
.ui-menu .not-active-flag {
display: inline-block;
height: 0;
width: 0;
margin-top: 14px;
border-top: 7px solid #babbbd;
border-bottom: 7px solid transparent;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
}
/* 正三角 */
.ui-menu .active-flag {
display: inline-block;
height: 0px;
width: 0;
margin-top: 7px;
border-top: 7px solid transparent;
border-bottom: 7px solid #fff;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
}
数组数据过滤
let find = this.menuData.filter(d=>d.id==mid);
if (find.length> 0) {
find[0].open = !find[0].open ;
}
组件代码
<template>
<div class="flex flex-col ui-menu padding-top-s scroll">
<div class="item" v-for="item in menuData">
<div class="lh master flex flex-space-between pointer cannotselect" @click="mClick(item.id)">
<div class="flex flex-center-cz">
<div class="left margin-right-l" :class="{'active': activeMasterItemId==item.id}" ></div>
<div class="text" :class="{'active-text': activeMasterItemId==item.id}" >{
{item.name}}</div>
</div>
<div class="margin-right-l"
:class="{'not-active-flag': !item.open, 'active-flag': item.open}" ></div>
</div>
<div class="details" v-if="item.open" v-for="detail in item.children">
<div class="lh detail flex pointer cannotselect" :class="{'active': activeDetailItemId==detail.id}"
@click="dClick(detail)" @mouseover="mouseover(item.id)" @mouseout="mouseout()">
<div class="text">{
{detail.name}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'Menu',
props:{
menuData:{}
},
data() {
return {
activeMasterItemId : null,
activeDetailItemId: null
}
},
methods:{
mouseover(mid) {
this.activeMasterItemId = mid
},
mouseout() {
this.activeMasterItemId = 0
},
mClick(mid){
let find = this.menuData.filter(d=>d.id==mid);
if (find.length> 0) {
find[0].open = !find[0].open ;
}
},
dClick(item) {
this.activeDetailItemId = item.id;
this.$emit("menuClick", item)
}
}
}
</script>
调用组件代码
<template>
<div class="body">
<div class="table">
<div class="filter font-bold">组件库(四) 导肮菜单</div>
<div class="margin-top-l margin-left-l flex flex-center-cz">
<my-menu :menuData="menuData" @menuClick="menuClick" class="my-menu"></my-menu>
</div>
</div>
</div>
</template>
<script>
/*
名称:组件库(四) 导肮菜单
作者:唐赢
时间:2023-3-12
*/
import MyMenu from '@/components/menu/Menu'
export default {
name: 'MenuDemo',
components: {
MyMenu
},
data () {
return {
menuData : [
{
"id":1,
"name":"基础资料",
"url":"",
"level":1,
"open": false,
"children":[
{
"id":2,
"name":"经销商",
"url":"",
"level":2
},
{
"id":3,
"name":"品牌档案",
"url":"",
"level":2
}
]
},
{
"id":4,
"name":"业务管理",
"url":"",
"level":1,
"open": false,
"children":[
{
"id":5,
"name":"入库单",
"url":"",
"level":2
},
{
"id":6,
"name":"出库单",
"url":"",
"level":2
}
]
}
]
}
},
methods: {
menuClick(item) {
console.log("click", item);
}
}
}
</script>
<style scoped>
.body {
display: flex;
justify-content: center;
margin-top: 73px;
width: 100%;
}
.table {
background-color: #fff;
width: 1080px;
min-height: 800px;
box-shadow: 0px 3px 6px rgba(0, 0, 0, .1);
margin-bottom: 10px;
}
.filter {
display: flex;
height: 60px;
align-items:center;
background-color: #fff;
font-size: 18px;
justify-content: center;
border-bottom: 1px solid rgba(0, 0, 0, .2);;
}
.my-menu {
width: 350px;
height: 500px;
}
</style>
相关文章: