1、新建一个名为ContextMenu.vue的文件
<template>
<div ref="containerRef">
<slot></slot>
<Teleport to="body">
<Transition @beforeEnter="handleBeforeEnter" @enter="handleEnter" @afterEnter="handleAfterEnter">
<div v-if="showMenu" class="context-menu" :style="{ left: x + 'px', top: y + 'px' }">
<div class="menu-list">
<!-- 添加菜单的点击事件 -->
<div @click="handleClick(item)" class="menu-item" v-for="(item, i) in menu" :key="item.label">
{{ item.label }}
</div>
</div>
</div>
</Transition>
</Teleport>
</div>
</template>
<script setup>
import { ref } from 'vue';
import useContextMenu from './useContextMenu';
const props = defineProps({
menu: {
type: Array,
default: () => [],
},
});
const containerRef = ref(null);
const emit = defineEmits(['select']);
const { x, y, showMenu } = useContextMenu(containerRef);
// 菜单的点击事件
function handleClick(item) {
// 选中菜单后关闭菜单
showMenu.value = false;
// 并返回选中的菜单
emit('select', item);
}
function handleBeforeEnter(el) {
el.style.height = 0;
}
function handleEnter(el) {
el.style.height = 'auto';
const h = el.clientHeight;
el.style.height = 0;
requestAnimationFrame(() => {
el.style.height = h + 'px';
el.style.transition = '.5s';
});
}
function handleAfterEnter(el) {
el.style.transition = 'none';
}
</script>
<style lang="scss" scoped>
.context-menu{
position: absolute;
.menu-list{
padding:0 10px;
box-shadow: 0 0 2px 2px #f1f1f1;
background: #fff;
.menu-item{
padding: 4px 5px;
text-align: center;
cursor: pointer;
&:hover{
color: #0073e5;
}
}
}
}
</style>
2、新建useContextMenu.ts文件
import { onMounted, onUnmounted, ref } from "vue";
export default function (containerRef) {
const showMenu = ref(false);
const x = ref(0);
const y = ref(0);
const handleContextMenu = (e) => {
e.preventDefault();
e.stopPropagation();
showMenu.value = true;
x.value = e.clientX;
y.value = e.clientY;
};
function closeMenu() {
showMenu.value = false;
}
onMounted(() => {
const div = containerRef.value;
div.addEventListener("contextmenu", handleContextMenu);
window.addEventListener("click", closeMenu, true);
window.addEventListener("contextmenu", closeMenu, true);
});
onUnmounted(() => {
const div = containerRef.value;
div.removeEventListener("contextmenu", handleContextMenu);
window.removeEventListener("click", closeMenu, true);
window.removeEventListener("contextmenu", closeMenu, true);
});
return {
showMenu,
x,
y,
};
}
3、使用方式如下:
<ContextMenu :menu="[
{ label: '添加' },
{ label: '编辑' },
{ label: '删除' },
{ label: '查看' },
{ label: '复制' },
]" @select="select($event.label)">
<div class="edit-mian-box">
<div class="edit-box">11111</div>
</div>
</ContextMenu>
效果图如下:
