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

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

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和其他封装会怎么进行,看项目咋说吧,时间不太充裕。

演示视频

Vue 3中的Element UI Plus是一个基于Vue 3的组件库,它是Element UI的升级版本,提供了许多现代化的UI组件,包括`el-table`。在`el-table`中实现虚拟滚动(Virtual Scroll)是一种优化大数据量表格渲染的技术,它通过只渲染可视区域内的行来提高性能。 在Vue 3的Element UI Plus中,实现虚拟滚动可以通过`v-infinite-scroll`指令来完成。这个指令允许你在表格滚动到接近底部时触发加载更多数据的操作,而不需要一次性加载所有数据。然而,需要注意的是,Element UI Plus本身并不直接提供一个虚拟滚动的实现,你可能需要结合其他的虚拟滚动库,比如`v-virtual-scroller`,来实现这一功能。 使用虚拟滚动库,你可以将`el-table`包裹在虚拟滚动组件中,并提供必要的数据和方法来处理数据的加载和渲染。这样可以显著减少DOM操作,提高大数据量表格的渲染性能。 以下是使用虚拟滚动的一个基本示例: ```vue <template> <v-virtual-scroller :data="tableData"> <template v-slot="{ item }"> <el-table :data="item" style="width: 100%"> <!-- 表格列定义 --> <el-table-column prop="date" label="日期" width="180"></el-table-column> <!-- 其他列定义 --> </el-table> </template> </v-virtual-scroller> </template> <script> import { ref } from 'vue'; import { ElTable, ElTableColumn } from 'element-plus'; import { VVirtualScroller } from 'v-virtual-scroller'; export default { components: { VVirtualScroller, ElTable, ElTableColumn }, setup() { const tableData = ref([]); // 假设这里有一个方法来加载数据 const loadData = () => { // 更新tableData或分页加载更多数据 }; return { tableData, loadData }; } }; </script> ``` 在上述示例中,`v-virtual-scroller`是虚拟滚动组件,`el-table`是Element UI Plus的表格组件,它会根据数据更新来动态渲染表格的每一行。`v-slot`指令用于定义虚拟滚动的内容模板,其中`item`代表每个渲染的行的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值