1) 效果,右键单击单元格,打开菜单弹窗:
点击菜单选项,可选择只读/编辑,可在只读/编辑方法中,拿到该行列表格的数据,进行相关操作
2) 思路
1、右键菜单组件 出现的时机,是右键单击table表格@row-contextmenu ,Element-Plus有提供;且需要阻止右键单击默认事件@contextmenu.prevent。
2、右键菜单组件 出现的位置,根据右键单击table表格的位置 对 右键菜单组件的位置进行设置。
3、右键菜单组件 展示内容,数据的传递 textList 和 点击事件的位置clickXY(决定右键菜单组件出现的位置,需要在视口内)。
3、右键菜单组件 事件传递,这里没有使用emit的方式,而是调用textList数组对象中fnn字段传递给子组件的,子组件调用就可以触发 父组件定义的方法。
4、右键菜单组件 如何关闭,右键单击打开,左键单击关闭,需要监听点击点击事件的e.button,值如为 0:鼠标左键、 1:滚轮按钮或中间按钮(如果有)、 2:鼠标右键
3) 简单的写一下.vue文件代码
前端代码在这里:https://github.com/wwaini/tao-vue3/tree/release240625
后端代码笔者用node写的,在这里:https://github.com/wwaini/tao-express
父组件 (代码中有详细备注)
<template>
<div>
<!-- @contextmenu.prevent 阻止默认事件 -->
<el-table @row-contextmenu="rightClickFn" @contextmenu.prevent :data="tableData" style="width: 100%">
<el-table-column prop="date" label="Date" width="180" />
<el-table-column prop="name" label="Name" width="180" />
<el-table-column prop="address" label="Address" />
</el-table>
<right-menu :textList="textList" :clickXY="clickXY"></right-menu>
</div>
</template>
<script setup>
import rightMenu from './component/index.vue'
import { reactive } from 'vue';
let tableData = reactive([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
const textList = reactive([])
const clickXY = reactive({})
const rightClickFn = (row, column, event) => {
Object.assign(textList,
[
{
// 使用回调函数的方式fnn,定义在父组件,在子组件调用即可触发
icon: 'view', text: '只读', fnn: view,
params: { row, column, event }
},
{
icon: 'edit', text: '编辑', fnn: edit,
params: { row, column, event }
}
]
)
Object.assign(clickXY,
{
position: {
x: event.clientX,
y: event.clientY
}
}
)
}
const view = (val) => {
// val拿到该行该列的信息
console.log('view-----', val);
}
const edit = (val) => {
// val拿到该行该列的信息
console.log('edit-----', val);
}
</script>
<style scoped lang="scss"></style>
子组件 - 右键菜单组件
<!-- 右键菜单功能 -->
<template>
<div id="rightMenu">
<ul class="table-right-menu">
<li @click="fn1(item)" v-for="(item) in textList" :key="item.text">
<el-icon :size="15">
<View v-if="item.icon === 'view'" />
<Edit v-if="item.icon === 'edit'" />
</el-icon>
{{ item.text }}
</li>
</ul>
</div>
</template>
<script setup>
import { defineProps, watch } from "vue";
const props = defineProps({
textList: {
type: Array,
default: () => []
},
clickXY: {
type: Object,
default: () => { }
}
})
const hide = (e) => {
if (e.button === 0) {
let positionXY = document.getElementById('rightMenu')
positionXY.style.display = 'none'
// 接触监听事件
document.removeEventListener("mouseup", hide)
}
}
const fn1 = (item) => {
item.fnn(item);
}
watch(
() => props.clickXY.position,
(val) => {
let x = val.x; // 获取x轴坐标
let y = val.y; // 获取y轴坐标
let innerWidth = window.innerWidth; // 获取页面可是区域宽度,即页面的宽度
let innerHeight = window.innerHeight; // 获取可视区域高度,即页面的高度
let menuHeight = props.textList.length * 30 // 弹窗高
let menuWidth = 100 // 弹窗宽
let positionXY = document.getElementById('rightMenu')
positionXY.style.display = 'block'
// 如果点击点 在视口最右方或者最下方 保证弹窗显示在视口内
positionXY.style.top = (y + menuHeight > innerHeight ? innerHeight - menuHeight - 10 : val.y) + 'px'
positionXY.style.left = (x + menuWidth > innerWidth ? innerWidth - menuWidth - 10 : val.x) + 'px'
// false 表示 hide 这个事件处理函数将在鼠标点击(mouseup)事件的冒泡阶段被调用。
// 如果为true,表示捕获阶段调用
document.addEventListener("mouseup", hide, false);
}
)
</script>
<style scoped>
#rightMenu {
width: 108px;
position: fixed;
z-index: 999;
display: none;
background: #fff;
box-shadow: 0 0 10px #ccc;
border-radius: 5px;
.table-right-menu {
line-height: 30px;
text-align: center;
font-size: 12px;
padding-left: 0;
li {
height: 30px;
display: flex;
justify-content: space-evenly;
padding: 0 15px;
align-items: center;
}
}
}
</style>
如有不足,欢迎指正。
不要忽视你达成的每个小目标,它是你前进路上的垫脚石。冲!