首先,我们先看下阿里云的导航菜单的样式,对这个样式有一个了解。
这个菜单,类似于那种树形菜单,用v-for循环就行了这样的菜单,可以看下这个Vue + ElementUI 手撸后台管理网站基本框架(三)登录及系统菜单加载
###首先,我们的数据模式要可配的,使用json数据格式,用递归实现
menuList:[{
label:"菜单一",
children:[{
label:"二级菜单_1",
children:[{
label:"三级菜单_1",
children:[{
label:"四级菜单_1"}]}]},{
label:"二级菜单_2",}]},{
label:"菜单二",
children:[{
label:"二级菜单",
children:[{
label:"三级菜单_1"}]}]}],
我们先看一下,我们生成的html代码的样式
<divclass="cascader"><divclass="cascader-panel"><ul><liclass="cascader-item"><p>菜单一</p></li><liclass="cascader-item"><p>菜单二</p></li></ul><divclass="cascader-panel"><ul><liclass="cascader-item"><p>二级菜单_1</p></li><liclass="cascader-item"><p>二级菜单_2</p></li></ul><divclass="cascader-panel">
...</div></div></div></div>
其实就是cascader-panel里套着cascader-panel,自己套自己,就能用递归来实现.
cascaderpanel.vue文件
<template><divclass="cascader-panel"><ulv-if="data && data.length"><li:class="[{isactive:currentIndex===index}]"v-for="(item,index) in data":data="item":key="item.id"@mouseenter="showChild(item,index)"><p>{{item.label}}</p></li></ul><cascader-panelv-if="childMenu && childMenu.length":data="childMenu"></cascader-panel></div></template><script>exportdefault{
name:"CascaderPanel",
props:{
data: Array},data(){return{
childMenu:[],
currentIndex:-1,};},
watch:{data(){this.childMenu=[];}},
methods:{showChild(item,index){this.currentIndex=index;this.childMenu= item.children;},}};</script><stylescoped>.cascader-panel{display: flex;height: 100%;}.isactive{color: blue;}li{width: 120px;cursor: pointer;}</style>
调用的时候,我是在app.vue中调用的.
代码如下:
<template><divid="app"><div@mouseenter="showall()"@mouseleave="showaleave()"><button>主菜单</button><divclass="cascader"v-show="show"><cascader-panel:data="menuList"></cascader-panel></div></div><p>111111111111111111111111111111111111111111111111111111111111111111111111</p></div></template><script>import CascaderPanelfrom"./components/CascaderPanel";exportdefault{
components:{
CascaderPanel},
props:{
data: Array,},data(){return{
menuList:[{
label:"菜单一",
children:[{
label:"二级菜单_1",
children:[{
label:"三级菜单_1",
children:[{
label:"四级菜单_1"}]}]},{
label:"二级菜单_2",}]},{
label:"菜单二",
children:[{
label:"二级菜单",
children:[{
label:"三级菜单_1"}]}]}],
show:false,}},
methods:{showall(){this.show=true;},showaleave(){this.show=false;},}};</script><style>.cascader{position: absolute;height: 100%;background-color: #eee;}</style>
此时的效果
现在有四个问题(仔细观察图片,或者自己运行代码)
1.鼠标离开按钮"主菜单"时,级联菜单的不隐藏,要离开很远,才隐藏(这是因为我们把button和级联菜单放在了一个div里,而mouseenter事件绑定在了这个div上,只有离开这个div,级联菜单才能隐藏.)
所以我们把button和div添加一样的width和height,这样就好了
.btn,.div{
height: 50px;
width: 100px;
}
2.当我们第二次进入按钮上时,它打开的是你上次最后离开是的样子,
找一个临时变量,来存取数据,当鼠标进入btn时,数据存入,离开,数据清空.
<cascader-panel :data="list"></cascader-panel>
showall(){
this.show=true;
this.list=this.menuList;
},
showaleave(){
this.show=false;
this.list=[];
},
3.跟上一个问题相似,当你进入菜单一下面的菜单时,在进入其他菜单,再回来是,菜单一下面的还是有hover样式.
这个样式是这样添加的
我们把这个currentIndex 赋值了,但是并没有清空,所以我们监听这个值,只要它变化,就变成默认-1(-1是不存在)就好了.
watch: {
data() {
this.childMenu= [];
this.currentIndex= -1;
}
},
4 this.childMenu的清空也是这个原理.(如果不清空,就一直存在)
这个问题,我在li下面加一个空白标签,给他添加一个mouseenter的方法(如果有更好的方法,可以提供给我)
<div @mouseenter="enterul()" style="height:100%;"></div>
enterul(){
this.currentIndex = -1;
this.childMenu = [];
}
目前就是这些,这个代码拆的不是很大,就是一个组件,一个调用.
源码地址级联菜单
还有一个拆分比较细的,也可以看看级联菜单细分
有更好的方法也可以提供给我.
---------------------------------2018.4.8更新--------------------------------------------
1.添加路由跳转
在级联导航的最后一层才有跳转的链接
所以,我们判断path的值就行
<liclass="cascader-item"><p @click="router(data.path)">{{ data.label}}</p></li>router(path){if(path!=undefined){
console.log("path11111111",path);this.$router.push("/hello")}},
2.清空this.childMenu问题
上边最后一点
我们添加了一个空的100%div,当鼠标在这个空白区域时,清空。
这个时所有都布局高度都是100%时,没有问题,但是高度为一定值时,就有问题
(li 标签有高度,100%div会超出他的父级高度)鼠标超出绿色区域,菜单就应该关闭,但是红色区域超出,导致不关闭
解决方法
在 ul上添加方法
handlemouseover(e){
console.log("this is over",e)if(e.srcElement.nodeName=="LI"){return}else{this.currentIndex=-1;this.childMenu=[];}},
git代码地址级联菜单细分