tab右击菜单功能
1、需求:当用户打开多个页面的时候,tab还要手动一个个点击删除就很麻烦,就需要一个批量删除的功能,比如右击弹出一个菜单进行批量删除

2、思路:
2-1、先弄一个全局定位的菜单模块,隐藏掉
2-2、给tabs绑定一个虚拟dom,获取它里面的子dom列表,因为游览器右击会有默认菜单,所以需要对子dom列表进行遍历来取消浏览器事件,并设置它们的右击事件
2-3、当在tab上右击的时候就会触发右击事件获取当前鼠标的坐标及当前点击的tab信息并显示菜单模块,用鼠标的坐标去设置菜单模块的位置并保存选中的tab信息用于处理删除时的功能
2-4、菜单出现后需要在点击调用功能后隐藏,就需要全局监听点击事件了,当在其他地方点击的时候就隐藏菜单模块
3、实现:
3-1、菜单模块
<ul class="menu" v-show="menuShow" :style="`top:${menuXY.y}px;left:${menuXY.x}px;`"> <li class="menu_item" @click="clickMenuItem(item.code)" v-for="item in menu" :key="item.title"> {{ item.title }} </li> </ul>
.menu { position: fixed; top: 0; left: 0; width: 100px; box-shadow: 3px 3px 3px rgba($color: #ccc, $alpha: 1); transition: 0.3s; background-color: #f5f5f5; z-index: 4; .menu_item { width: 100px; height: 32px; display: flex; justify-content: center; align-items: center; font-size: 14px; cursor: pointer; &:hover { background-color: #2998e8; color: #fff; } } }
3-2、配置tab右击事件
setRightClick() { //获取tabs的dom let tabs = this.$refs.tabs //获取tabs的子dom列表 let tabDom = tabs.$el.querySelectorAll('div[role=tab]') // 循环配置右击事件 tabDom.forEach(e => { //触发右击事件的方法 e.oncontextmenu = (el) => { if (el.button == 2) { //设置点击的tab名称 用于获取位置 this.clickNmae = el.path[0].innerText // console.log(name.split('/')) //去掉浏览器默认事件 el.preventDefault() //获取当前鼠标坐标来设置菜单栏的位置 this.menuXY.y = event.clientY this.menuXY.x = event.clientX + 5 //显示菜单栏 this.menuShow = true } } }); },
3-3、点击菜单触发需要功能
clickMenuItem(code) { switch (code) { case 'menuClose': this.menuClose() break; case 'menuCloseLeft': this.menuCloseLeft() break; case 'menuCloseRight': this.menuCloseRight() break; case 'menuCloseOther': this.menuCloseOther() break; } }, menuClose() { this.tabRemove(this.$store.state.pageTab.find(e => e.meta.title == this.clickNmae).fullPath) }, menuCloseLeft() { this.$store.state.pageTab.find(e => { if (e.meta.title !== this.clickNmae) { this.tabRemove(e.fullPath) } return e.meta.title == this.clickNmae }) }, menuCloseRight() { this.$store.state.pageTab.slice().reverse().find(e => { if (e.meta.title !== this.clickNmae) { this.tabRemove(e.fullPath) } return e.meta.title == this.clickNmae }) }, menuCloseOther() { this.$store.state.pageTab.map(e => { if (e.meta.title !== this.clickNmae) { this.tabRemove(e.fullPath) } }) },
4、完整代码
<template>
<el-tabs
ref="tabs"
v-model="$store.state.tabIndex"
type="card"
closable
@tab-click="tabClick"
@tab-remove="tabRemove"
>
<el-tab-pane
:key="item.name"
v-for="item in $store.state.pageTab"
:label="item.meta.title"
:name="item.fullPath"
>
</el-tab-pane>
<ul class="menu" v-show="menuShow" :style="`top:${menuXY.y}px;left:${menuXY.x}px;`">
<li class="menu_item" @click="clickMenuItem(item.code)" v-for="item in menu" :key="item.title">
{{ item.title }}
</li>
</ul>
</el-tabs>
</template>
<script>
export default {
name: 'headerTab',
components: {
},
props: {
},
watch: {
$route() {
this.setRightClick()
}
},
data() {
return {
menuXY: {
x: 0,
y: 0
},
menu: [
{ title: '关闭', code: "menuClose" },
{ title: '关闭左侧', code: "menuCloseLeft" },
{ title: '关闭右侧', code: "menuCloseRight" },
{ title: '关闭其他', code: "menuCloseOther" },
],
menuShow: false,
clickNmae: ''
};
},
beforeUnmount() {
//页面卸载时去除监听 防止占用资源
document.body.removeEventListener('click', this.hideMenu)
},
mounted() {
//监听全页面,如果有点击就隐藏右击菜单
document.body.addEventListener('click', this.hideMenu)
},
methods: {
clickMenuItem(code) {
switch (code) {
case 'menuClose':
this.menuClose()
break;
case 'menuCloseLeft':
this.menuCloseLeft()
break;
case 'menuCloseRight':
this.menuCloseRight()
break;
case 'menuCloseOther':
this.menuCloseOther()
break;
}
},
menuClose() {
this.tabRemove(this.$store.state.pageTab.find(e => e.meta.title == this.clickNmae).fullPath)
},
menuCloseLeft() {
this.$store.state.pageTab.find(e => {
if (e.meta.title !== this.clickNmae) {
this.tabRemove(e.fullPath)
}
return e.meta.title == this.clickNmae
})
},
menuCloseRight() {
this.$store.state.pageTab.slice().reverse().find(e => {
if (e.meta.title !== this.clickNmae) {
this.tabRemove(e.fullPath)
}
return e.meta.title == this.clickNmae
})
},
menuCloseOther() {
this.$store.state.pageTab.map(e => {
if (e.meta.title !== this.clickNmae) {
this.tabRemove(e.fullPath)
}
})
},
hideMenu() {
this.menuShow = false
},
setRightClick() {
//获取tab列表dom
let tabs = this.$refs.tabs
//获取tab列表的子dom列表
let tabDom = tabs.$el.querySelectorAll('div[role=tab]')
// 循环配置右击事件
tabDom.forEach(e => {
//触发右击事件的方法
e.oncontextmenu = (el) => {
if (el.button == 2) {
//设置点击的tab名称 用于获取位置
this.clickNmae = el.path[0].innerText
// console.log(name.split('/'))
//去掉浏览器默认事件
el.preventDefault()
//获取当前鼠标坐标来设置菜单栏的位置
this.menuXY.y = event.clientY
this.menuXY.x = event.clientX + 5
//显示菜单栏
this.menuShow = true
}
}
});
},
tabRemove(targetName) {
this.$store.commit('removePageTab', targetName)
},
tabClick() {
if (this.$route.fullPath !== this.$store.state.tabIndex) {
this.$router.push(this.$store.state.tabIndex)
}
},
}
}
</script>
<style lang="scss" scoped>
.menu {
position: fixed;
top: 0;
left: 0;
width: 100px;
box-shadow: 3px 3px 3px rgba($color: #ccc, $alpha: 1);
transition: 0.3s;
background-color: #f5f5f5;
z-index: 4;
.menu_item {
width: 100px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
cursor: pointer;
&:hover {
background-color: #2998e8;
color: #fff;
}
}
}
::v-deep .is-active {
background-color: #eff1f4;
color: #333 !important;
font-weight: bold;
}
::v-deep .el-tabs__nav {
border: none !important;
}
::v-deep .el-tabs__item {
border: none !important;
color: #ccc;
}
</style>
5、效果


浙公网安备 33010602011771号