当前位置: 首页 > article >正文

vue2,vue3基于elementUI的el-table实现复制粘贴功能

vue2,vue3基于elementUI的el-table实现复制粘贴功能

  • vue2
  • vue3

1、先声明一下,为啥又有vue2和vue3呢,因为老项目要改造成vite+ts+vue3,时间紧,来不及全部转换,所以就有了componentApi和optionsApi共存的情况

2、单页面使用,全局未实现

vue2

  1. 既然是基于el-table呢就有现成的methods可以使用
    @row-contextmenu="rowContextmenu"
    @row-click="rowClick"
<template>
	<el-table
      ref="multipleTableRef"
      v-loading="loading"
      :data="state.dataList"
      style="width: 100%; margin-bottom: 20px"
      border
      :cell-style="cellStyle"
      @sort-change="sortChange"
      :header-cell-style="headerCellStyle"
      @selection-change="handleSelectionChange"
      @row-contextmenu="rowContextmenu"
      @cell-mouse-leave="cellMouseLeave"
      @row-click="rowClick"
  >
	    <el-table-column  align="center" prop="status" label="是否正确" show-overflow-tooltip width="130">
		      <template #default="{ row }">
		        <span v-if="row.status === 1">正确</span>
		        <span v-if="row.status === 2">错误</span>
		      </template>
        </el-table-column>
</el-table>
  <div v-if="position.show"
       :style="{ position: 'fixed', top: position.y + 'px', left: position.x + 'px', zIndex: 9999, display: 'flex',justifyContent:'center',alignItems:'center',flexFlow:'column',borderRadius:'5px' }"
       class="context-menu">
    <!-- 菜单内容 -->
    <span class="posItem" @click="copyText('column')"><el-icon><DocumentCopy/></el-icon>复制当前行</span>
    <span class="posItem" @click="copyText('row')"><el-icon><DocumentCopy/></el-icon>复制当前列</span>
  </div>
</template>
<script>
export default {
	date() {
		return {
			position: {
		        x: 0,
		        y: 0,
		        show: false,
		        row: null,
		        column: null,
	       },
	       columnList: [ // 需要复制的 prop
		        'orderCodes',
		        'bookCode',
		        'orderExecManagerName',
		        'logisticsManagerName',
		        'customerName',
		        'startPortName',
		        'endPortName',
		        'endPortCountryName',
		        'outCountryName',
		        'contractDealstyle',
		        'shipMentName',
		        'requireWeek',
		        'expectEtd',
		        'bookArrivalDate',
		        'vendorName',
		        'bookShipName',
		        'preBookStatusName',
		        'actualVolumeBoxType',
		        'cntCount',
		        'forwardAgent',
		        'forwardAgentContact',
		        'goodTypeName',
		        'deptName',
		        'prodName',
		        'bookTime',
		        'bookTrustTime',
		        'requireMonth',
		        'requireYear',
		        'bookComments',
		        'forwardAgent',
		        'agentName',
		        'customsName',
		        'bookingRemark',
		        'originBillNum',
		        'standingBookRemark']
			}
	},
	 methods: {
	     /**
	     * @description: copyText 复制行或者列点击事件,
	     * @return {type} 需要打印的行或者列
	     * row和colume俩参数我给搞混了,后续考虑封装成npm插件的可行性,就没改,可以拿来直接用
	     * 下方只解释代码逻辑
	     * @return {row} 列:拿到点击的el-table的prop后,循环遍历出所有的值,然后调用复制
	     * @return {column} 行:因为后台返的不全是汉字,例如<template #default="{ row }"> 需要在行内重新组合,所以,要么在获取数据的时候就重新给后端返回的数据复制,要么就不复制。
	     * @return {columns}  需要知道要打印哪一个prop,从表格中拿数据,然后复制(想直接拿dom,有点复杂,暂时先实现功能)
	     */
	    copyText(type){
	      if (type === 'row') {
	        const prop = this.position.column.property
	        const list =this.tableData?.map(item => {
	          return item[prop]
	        })
	        this.copyTextToClipboard(list.join('\n'))
	      }
	      if (type === 'column') {
	        let ls = []
	        for (let i = 0; i < this.columnList.length; i++) {
	          const columns = this.columnList[i]
	          ls.push(this.position.row[columns])
	        }
	        this.copyTextToClipboard(ls.join('\t'));
	      }
	      this.position.show = false;
	    },
  	     /**
	     * @description: rowContextmenu 获取鼠标的右键点击事件,弹窗展示的位置
	     * @return {event.preventDefault()} 阻止浏览器的默认右键弹窗,展示咱的自定义弹窗
	     */
	    rowContextmenu(row, column, event){
	      console.log(row, column, event, 'fffff')
	      event.preventDefault()  // 阻止默认右键菜单
	      this.position.x = event.clientX + 20;
	      this.position.y = event.clientY + 20;
	      this.position.row = row;
	      this.position.column = column;
	      this.position.show = true;
	    },
    	 /**
	     * @description: copyTextToClipboard 复制到浏览器的粘贴板
	     * @return {window.isSecureContext} 浏览器安全环境,如果项目的线上不是以https开头,而是以http开头的,就不安全,浏览器不让你复制
	     * else为啥这么做,,是为了绕过安全。具体请参考大佬的解释:https://blog.csdn.net/weixin_42190844/article/details/138336318
	     */
	    async copyTextToClipboard(text) {
	      if (window.isSecureContext) {
		      try {
		        await navigator.clipboard.writeText(text);
		        this.$message.success('复制成功')
		      } catch (err) {
		        console.error('Failed to copy: ', err);
		      }
	      } else {
		        // copyText(text)
		        let textArea = document.createElement('textarea')
		        textArea.value = text;
		        textArea.style.position = 'absolute';
		        textArea.style.opacity = 0;
		        textArea.style.left = '-99999999px';
		        textArea.style.top = '-99999999xp';
		        document.body.appendChild(textArea);
		        textArea.focus;
		        textArea.select();
		        let res = new Promise((res,rej)=> {
		          res(() => {
		            document.execCommand('copy');
		            textArea.remove()
		          })
		          rej(false)
		        })
		        res.then(res => {
		          res()
		          this.$message.success('复制成功')
		        })
	      }
      }
      rowClick (row) {
	    this.position.show = false;
	  }
    },
}
</script>
<style lang="scss" scoped>
.context-menu {
  background-color: white;
  border: 1px solid #ccc;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.posItem {
  display: block; cursor: pointer;
  padding: 0 20px;
  height: 35px;
  line-height: 35px;
  &:hover {
    background: #d5e7f9;
  }
}
</style>

vue3

<template>
<el-table
      ref="multipleTable"
      v-loading="loading"
      :data="tableData"
      style="width: 100%; margin-bottom: 20px; margin-top: 20px"
      :default-sort="{ prop: 'associatedOrder', order: 'descending' }"
      border
      @selection-change="handleSelectionChange"
      @sort-change="sortChange"
      @row-contextmenu="rowContextmenu"
      @cell-mouse-leave="cellMouseLeave"
      @row-click="rowClick"
  >
</template>
<script setup lang="ts">
const columnList = [
  'orderCodes',
  'bookCode',
  'orderExecManagerName',
  'regionName',
  'customerName',
  'startPortName',
  'endPortName',
  'endPortCountryName',
  'outCountryName',
  'contractDealstyle',]
const position = reactive({
  x: 0,
  y: 0,
  show: false,
  row: null,
  column: null,
})
const copyText = (type) => {
  if (type === 'row') {
    const prop = position.column.property
    const list = state.dataList?.map(item => {
      return item[prop]
    })
    copyTextToClipboard(list.join('\n'))
  }
  if (type === 'column') {
    let ls = []
    for (let i = 0; i < columnList.length; i++) {
      const columns = columnList[i]
      ls.push(position.row[columns])
    }
    copyTextToClipboard(ls.join('\t'));
  }
  position.show = false;
}
const rowContextmenu = (row, column, event) => {
  console.log(row, column, event, 'fffff')
  event.preventDefault()  // 阻止默认右键菜单
  position.x = event.clientX + 20;
  position.y = event.clientY + 20;
  position.row = row;
  position.column = column;
  position.show = true;

}
const copyTextToClipboard = async (text) => {
  if(window.isSecureContext){
    try {
      await navigator.clipboard.writeText(text);
      ElMessage.success('复制成功')
    } catch (err) {
      console.error('Failed to copy: ', err);
    }
  } else {
    // copyText(text)
    let textArea = document.createElement('textarea')
    textArea.value = text;
    textArea.style.position = 'absolute';
    textArea.style.opacity = 0;
    textArea.style.left = '-99999999px';
    textArea.style.top = '-99999999xp';
    document.body.appendChild(textArea);
    textArea.focus;
    textArea.select();
    let res = new Promise((res,rej)=> {
      res(() => {
        document.execCommand('copy');
        textArea.remove()
      })
      rej(false)
    })
    res.then(res => {
      res()
      ElMessage.success('复制成功')
    })
  }
}
const cellMouseLeave = () => {
  // position.show = false;
}
const rowClick = (row) => {
  position.show = false;
}
</script>
<style lang="scss" scoped>
.context-menu {
  background-color: white;
  border: 1px solid #ccc;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.posItem {
  display: block; cursor: pointer;
  padding: 0 20px;
  height: 35px;
  line-height: 35px;
  &:hover {
    background: #d5e7f9;
  }
}
</style>

vue3的详解看vue2,后续关于dom和其他封装会怎么进行,看项目咋说吧,时间不太充裕。

演示视频


http://www.kler.cn/a/293883.html

相关文章:

  • Python提取PDF和DOCX中的文本、图片和表格
  • uniCloud云对象调用第三方接口,根据IP获取用户归属地的免费API接口,亲测可用
  • 解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url
  • 深入理解BERT模型配置:BertConfig类详解
  • leetcode hot100【LeetCode 114.二叉树展开为链表】java实现
  • MYSQL 库,表 基本操作
  • 【docker】基于docker-compose 安装elasticsearch + kibana + ik分词器(8.10.4版本)
  • HDFS工具类
  • 高级架构师备考计划
  • Maven持续集成(Continuous integration,简称CI)版本友好管理
  • tailwindcss在vue2中安装配置流程
  • Kafka大厂面试14问(附答案)
  • windows下php+nginx的wordpress配置教程和问题解决
  • Python绘制嫦娥奔月
  • IP和品牌有什么区别?
  • 深度学习每周学习总结N9:transformer复现
  • 牵手西安,产业园区如何“玩转”数字媒体产业?
  • 产品经理就业
  • 深度学习(三)-反向传播
  • mac 安装brew并配置国内源
  • 前端框架介绍
  • 昆明理工大学MBA工商管理学费
  • 二、再识Django
  • 彩虹数字屏保时钟 芝麻时钟开启个性化的时代 屏保怎么能少它
  • 马来西亚参访团走进数字人企业世优科技,共鉴元宇宙数字创新成果
  • 【vue、UI】使用 Vue2 和 Element UI 封装 CSV 文件上传组件,实现csv回显