目录
一、背景
项目需要,自定义菜单栏,有二级下拉菜单。点击后可跳到指定的路由页面。
二、源码
<template>
<div class="menubar-page">
<!-- 菜单栏 -->
<div class="menu-bar">
<span v-for="item of menus" :key="item.type"
class="menu-item"
:class="(activeMenu === item.type | subParentType === item.type) ? 'menu-item-active' : ''"
@click="menuClick(item)"
@mouseover="menuMouse($event, item, true)"
@mouseout="menuMouse($event, item, false)">
{{item.name}}
</span>
</div>
<!-- 子菜单列表 -->
<div :id="item.type+'Submenu'" class="sub-menu" v-for="item of submenus" :key="item.type"
v-show="showSubMenu && hoverMenu === item.type"
@mouseover="submenuMouse(item, true)"
@mouseout="submenuMouse(item, false)">
<div v-for="subitem of item.children" :key="subitem.type"
class="sub-menu-item"
@click="submenuClick(subitem, item)">
{{subitem.name}}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 菜单配置
menus: [
{
name: '首页',
type: 'first'
},
{
name: '科普知识',
type: 'science'
},
{
name: '旅游资源',
type: 'source',
children: [{
name: '海岛介绍',
type: 'island'
},{
name: '沙漠路线',
type: 'desert'
}]
},
{
name: '数据管理',
type: 'data',
children: [{
name: '热点访问',
type: 'visit'
},{
name: '热点路线',
type: 'hot'
}]
},
{
name: '分析评价',
type: 'evaluate',
children: [{
name: '数字货币',
type: 'map'
},{
name: '场景布局',
type: 'scene'
}]
}
],
// 子菜单列表
submenus: [],
// 激活菜单
activeMenu: 'first',
// hover 菜单
hoverMenu: 'first',
// 显示子菜单
showSubMenu: false,
// 子菜单的父菜单index
subParentType: ''
}
},
methods: {
// 父菜单 over 和 out
menuMouse(e, item, show) {
// 子菜单显示
this.showSubMenu = show;
// hover 显示
this.hoverMenu = item.type;
// 子菜单显示 left
if(item.children) {
let offsetLeft = e.target.offsetLeft;
document.getElementById(item.type+'Submenu').style.left = offsetLeft + 'px';
}
},
// 父菜单 click
menuClick(item) {
// 当前 menu
this.activeMenu = item.type;
// 路由跳转
if(!item.children) {
this.$router.push({ path: item.type === 'first' ? '/' : `/${item.type}` });
}
},
// 子菜单 over 和 out
submenuMouse(subitem, show) {
this.showSubMenu = show;
this.hoverMenu = subitem.type;
this.subParentType = show ? subitem.parentType : '';
},
// 子菜单 click
submenuClick(subitem, item) {
// 父 active 设置
this.activeMenu = item.type;
// 路由跳转
this.$router.push({ path: `/${subitem.type}` });
}
},
created() {// DOM渲染之前
// 有下拉框的菜单
for(let i = 0, len = this.menus.length; i< len; i++) {
let item = this.menus[i];
if(item.children) {
// 用于鼠标over子菜单时,父菜单active效果
item.parentType = item.type;
this.submenus.push(item);
}
}
// 获取路径
let split = window.location.href.split('/#/');
let pageType = split[1] ? split[1] : '';
// active 菜单设置
for(let i = 0, len = this.menus.length; i < len; i++) {
let menu = this.menus[i];
if(menu.children) {
for(let j = 0, l = menu.children.length; j < l; j++) {
let submenu = menu.children[j];
if(pageType === submenu.type) {
this.activeMenu = menu.type;
break;
}
}
}
else if(pageType === menu.type) {
this.activeMenu = pageType;
break;
}
}
}
}
</script>
<style lang="stylus" scoped>
.menubar-page {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #ccc;
}
.menu-bar{
text-align center
background #003466
height: 64px;
.menu-item {
display: inline-block;
width 240px
height: 64px;
line-height: 64px;
cursor: pointer;
color: white;
user-select:none;
&:hover {
background: #0147b2
}
}
.menu-item-active {
background: #0147b2
}
}
// 拉框菜单
.sub-menu {
position absolute
display inline-block
width 240px
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)
cursor: pointer;
user-select:none;
text-align center
z-index 1000
background white
}
.sub-menu-item {
height 50px
line-height 50px
&:hover {
color $subColor
background rgb(231,242,255)
}
}
</style>
三、知识点
生命周期 created:
1、联动子菜单和父菜单的 mouse over 监听效果。
2、配置中,type 与 页面路由名一致。可根据当前href的路由,初始化active效果