Vue3封装table表格右键菜单功能

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>


如有不足,欢迎指正。

不要忽视你达成的每个小目标,它是你前进路上的垫脚石。冲!

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3结合univerjs来实现电子表格并自定义右键菜单,通常会涉及到以下几个步骤: 1. **设置Vue项目环境**:首先,你需要创建一个Vue3项目。可以使用Vue CLI或者Vite等工具来搭建项目框架。 2. **集成univerjs电子表格库**:univerjs是一个功能丰富的前端表格库,可以通过npm或yarn等包管理工具将其安装到你的Vue项目中。 3. **初始化电子表格**:在Vue组件中,你可以引入并初始化univerjs电子表格。通常这涉及到设置表格的数据源、配置行列宽高等基础设置。 4. **添加自定义右键菜单功能**:在univerjs中,可以通过事件监听和命令模式来实现自定义右键菜单功能。具体来说,你可能需要监听表格右键事件(contextmenu事件),然后根据触发右键的位置来动态生成菜单项,并为每个菜单项绑定相应的命令或回调函数。 5. **实现右键菜单的交互逻辑**:当用户点击自定义的菜单项时,你将根据菜单项的功能编写对应的逻辑处理代码,比如复制、粘贴、插入行、删除行等操作。 这里给出一个简化的示例代码片段,展示如何在Vue组件中结合univerjs设置一个简单的自定义右键菜单: ```javascript <template> <div> <!-- 电子表格渲染区域 --> <div ref="spreadsheet"></div> <!-- 右键菜单 --> <div v-if="showContextMenu" class="context-menu"> <ul> <li @click="handleCopy">复制</li> <li @click="handlePaste">粘贴</li> <!-- 更多菜单项... --> </ul> </div> </div> </template> <script> import { ref, onMounted } from 'vue'; import { createUniver } from 'univerjs'; export default { setup() { const spreadsheet = ref(null); const showContextMenu = ref(false); let univerInstance; onMounted(() => { univerInstance = createUniver(spreadsheet.value); univerInstance.on('contextmenu', (e) => { e.preventDefault(); // 阻止默认右键菜单 showContextMenu.value = true; // 根据e的位置显示右键菜单 // ... }); }); const handleCopy = () => { // 实现复制逻辑 console.log('复制操作'); showContextMenu.value = false; }; const handlePaste = () => { // 实现粘贴逻辑 console.log('粘贴操作'); showContextMenu.value = false; }; return { spreadsheet, showContextMenu, }; }, }; </script> <style> .context-menu { /* 菜单样式 */ } </style> ``` 在上述代码中,我们创建了一个名为`spreadsheet`的ref变量指向电子表格的渲染区域,并通过`createUniver`函数初始化univerjs实例。监听了`contextmenu`事件来显示右键菜单,并为复制和粘贴菜单项绑定了点击事件处理函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值