目录
一、背景
最近在写一个聊天程序,要实现点击鼠标右键弹出相关的操作菜单栏,以实现相关功能的拓展。这里主要是记录下,如何在vue项目中实现这种功能。
二、步骤分析
2.1、监听鼠标右键事件
首先,我们需要阻止原默认的鼠标右键事件,弹出我们自定义的相关菜单。这里想到可以使用JavaScript的dom监听器来实现此功能。
javascript
// 监听快捷键事件,回调参数事件event
onMounted(
() => {
document.addEventListener('contextmenu', clickRightMouse)
}
)
onUnmounted(
() => {
document.removeEventListener('contextmenu', clickRightMouse)
}
)
// 鼠标右键监听
function clickRightMouse(event){
// 阻止默认事件触发
event.preventDefault();
// 编写触发自定义逻辑
}
后面从网上查询了相关资料,发现vue有简写的语法糖,等效使用JavaScript监听器实现的功能实现。
html
<!-- @contextmenu vue语法糖等效JavaScript对应的监听器 -->
<!-- .prevent vue事件修饰符,自动阻止默认事件运行 -->
<!-- handleRightClick 自定义事件运行逻辑 -->
<div @contextmenu.prevent="handleRightClick"></div>
2.2、自定义弹出框
点击鼠标右键,在光标所在位置的右侧弹出操作菜单,点击操作按钮,实现对应的操作逻辑。这里重要的是要在弹出框出现前,计算出弹出层的宽高位置。弹出框可以使用position: fiexd; 配合事件回调取出光标位置。
html
<template>
<div class="contactGroupList" @contextmenu.prevent="openMenu">
<!-- 动态菜单 -->
<teleport to=".contactGroupList" :defer="true">
<div
v-show="isShowMenu"
class="context-menu"
:style="{ top: `${mousePosition.y}px`, left: `${mousePosition.x}px` }"
>
<ul>
<li @click="handleAction('addGroup')">
<el-icon><Plus /></el-icon>添加分组
</li>
<li @click="handleAction('deleteGroup')">
<el-icon><DeleteFilled /></el-icon>删除分组
</li>
<li @click="handleAction('manageGroup')">
<el-icon><EditPen /></el-icon>重命名分组
</li>
</ul>
</div>
</teleport>
<div>
</template>
<script setup>
import { ref, reactive, markRaw, onBeforeMount, watch } from 'vue'
// 右键打开自定义菜单
const isShowMenu = ref(false)
const mousePosition = ref({ x: 0, y: 0 })
const openMenu = (e) => {
mousePosition.value = {
x: e.clientX,
y: e.clientY,
}
isShowMenu.value = true
document.addEventListener('click', closeMenu)
}
const closeMenu = () => {
isShowMenu.value = false
document.removeEventListener('click', closeMenu)
}
const handleAction = (action) => {
alert(`执行操作:${action}`)
closeMenu()
}
</script>
<style lang='scss' scoped>
.contactGroupList {
width: 100%;
height: 100%:
display: flex;
flex-direction: column;
// 联系人鼠标右键弹出菜单样式(弹出框挂载在contactList下的)
.context-menu {
position: fixed;
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border-radius: 4px;
z-index: 1000;
font-size: 14px;
}
.context-menu ul {
list-style: none;
padding: 0;
margin: 0;
min-width: 120px;
}
.context-menu li {
padding: 8px 12px;
cursor: pointer;
line-height: 100%;
display: flex;
flex-direction: row;
gap: 5px;
}
.context-menu li:hover {
background: #f5f5f5;
}
}
</style>
三、实现效果
