前言
我们在使用浏览器(例如chrome),或者一些IDE时,我们总会打开很多标签页,所以chrome和IDE提供了关闭所有、关闭右侧、关闭其他等批量关闭功能。
在BuildAdmin中,对导航栏的tab页同样也实现了这样的功能。如图所示:
可以看到,右键(contextmenu)点击tab就会弹出一个选项框,其中包括重新加载、关闭当前标签、关闭其他标签、当前标签全屏等功能。那么如何实现这样的一个弹出框,以及如何实现这些功能。
tab弹出框
BuildAdmin在src/components/contextmenu/index.vue中定义了弹出框组件。
从代码来看,就是使用了div,加ul、li标签,但是从class命名(以el-开头)来看,应该使用的是ElementPlus的组件渲染后的元素,这里先看弹出框效果,如下图。
接下来的工作就是实现弹出框、并填充内容,再实现各个功能模块。
实现弹出框
抛开BuildAdmin的代码不谈,如果让我自己来实现这样的弹出框组件,我肯定先去Element的官网看看什么组件符合我的预期。
Element提供的el-popover组件即可实现弹出框,直接拷贝官网代码,定义了一个ContextMenu.vue组件,实现如下:
trigger属性有click/focus/hover/contextmenu,选择contextmenu表示右键触发弹出框,插槽 #reference 是定义一个触发弹出框的元素,这里定义了一个按钮。
同事在ul中对props.items进行遍历渲染,props接收父组件传过来的值,tabs里面使用了ContextMenu组件,并绑定items传递标签列表。
其中ContextMenuItem是自定义的一个interface,用来定义标签字段。
export interface ContextMenuItem {
name: string
label: string
icon?: string
disabled?: boolean
}
disabled用来设置此标签功能是否可用,这个属性尤为关键。我们先看上面代码的渲染结果:
我们可以看到,在tab栏中出现了一个点击按钮,右键这个按钮就会出现弹出框,但是我的诉求是点击tab触发弹出框,这不太符合我们的要求。在研究了popover之后,发现el-popover的缺点:必须在插槽中定义一个按钮用来触发弹出框。
在Playground中进行测试,在删除了reference的slot之后,就会报错。
上面也说了BuildAdmin没有使用el-popover,使用的el-popover渲染后的html元素。通过对我使用的el-popover进行控制台查看元素,也证实了这一点:
所以,我使用的也是渲染后popover。原因有二:
- 必须绑定触发元素(按钮),将tab插入提供的reference插槽比较麻烦
- 弹出框箭头的位置是根据触发按钮长度来确定的,无法修改
所以,最后将控制台中渲染后的原始元素拷贝过来,只保留弹出框部分,去掉点击按钮。
再定义一些css样式。
css
.ba-contextmenu {
z-index: 9999;
}
.el-popper,
.el-popper.is-light .el-popper__arrow::before {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border: none;
}
.el-dropdown-menu__item {
padding: 8px 20px;
user-select: none;
}
.el-dropdown-menu__item .icon {
margin-right: 5px;
}
z-index设置成9999表示在弹出框位于最上层,user-select设置none,标签就无法被选中,其他的就是对间距的设置,可以按照自己需求调整。
这样就实现了弹出框组件,接下里就是要考虑如何将弹出框和每个tab绑定,并实现五个功能模块。
结语
这里先抛出第一个问题:在tab栏中点击哪里,弹出框就出现在哪里,这个是怎么实现的?