vue3+element-plus实现table表格整列的拖拽

参考文章:https://blog.csdn.net/candy0521/article/details/136470284

一、为防止原文章不见了将参考文章代码拷过来了(不好意思):这是参考文章的代码 可直接复制粘贴运行

<template>
  <div class="draggable-table">
    <el-table ref="tableRef"
              :data="tableData.data"
              :key="'table'+tableData.key"
              @header-dragend="handleHeaderDragend"
              border
              style="width: 100%">
      <template v-for="item of tableData.columnList">
        <el-table-column show-overflow-tooltip :prop="item.prop" :label="item.label"
                         :width="item.width"></el-table-column>
      </template>
    </el-table>
  </div>
</template>
<script lang="ts" setup>
import {nextTick, onMounted, reactive, ref} from "vue";
import Sortable from 'sortablejs';
 
const tableData = reactive({
  key: new Date().getTime(),
  data: [
    {
      id: 'id',
      name: 'name',
      amount1: 'amount1',
      amount2: 'amount2',
      amount3: 'amount3',
    },
    {
      id: '12987123',
      name: 'Tom',
      amount1: '165',
      amount2: '4.43',
      amount3: 12,
    },
    {
      id: '12987124',
      name: 'Tom',
      amount1: '324',
      amount2: '1.9',
      amount3: 9,
    },
    {
      id: '12987125',
      name: 'Tom',
      amount1: '621',
      amount2: '2.2',
      amount3: 17,
    },
    {
      id: '12987126',
      name: 'Tom',
      amount1: '539',
      amount2: '4.1',
      amount3: 15,
    },
  ],
  columnList: [
    {
      label: 'ID',
      prop: "id",
      width: "180"
    },
    {
      label: 'Name',
      prop: "name",
      width: "180"
    },
    {
      label: 'Amount1',
      prop: "amount1",
      width: "180"
    },
    {
      label: 'Amount2',
      prop: "amount2",
      width: "180"
    },
    {
      label: 'Amount3',
      prop: "amount3",
      width: "180"
    },
 
  ]
})
const tableRef = ref();
let sortable:Sortable;
onMounted(() => {
  initTableHeaderDrag(); // 初始化拖拽事件
})
 
function initTableHeaderDrag(){
  if(sortable){
    sortable.destroy();
  }
  let el = tableRef.value.$el.querySelector('.el-table__header-wrapper tr')
  sortable = Sortable.create(el, {
    animation: 150,
    onEnd(evt: any) {
      const oldItem = tableData.columnList[evt.oldIndex];
      tableData.columnList.splice(evt.oldIndex, 1);
      tableData.columnList.splice(evt.newIndex, 0, oldItem);
      tableData.key = new Date().getTime(); // 变更key,强制重绘table。如果不强制变更的话,会出现一些奇奇怪怪的问题,列宽度调整也会出现问题
      nextTick(() => {
        initTableHeaderDrag(); // 因为table被强制重新绘制,因此需要重新监听
      })
    }
  })
}
function handleHeaderDragend(newWidth, oldWidth, column, event){
  for(let item of tableData.columnList){
    if(item.label == column.label){
      item.width = newWidth;
    }
  }
  initTableHeaderDrag(); // 重新注册,防止变更宽度后无法拖动
}
</script>
<style scoped lang="scss">
 
</style>

注意: 整列的拖拽一定是 let el = tableRef.value.$el.querySelector('.el-table__header-wrapper tr')有些参考选择器的内容是body

二、以下是项目需求在以上代码的基础上修改

1、列表可以根据复选框的值动态显示表格里面显示隐藏的数据

2、实现的主要代码

 1、安装import Sortable from 'sortablejs';
 2、onMounted(()=>{
	init() //这个方法是请求接口获取到表格(tabelData.data)的数据
	 nextTick(() => {
    	initTableHeaderDrag(); // 初始化拖拽事件
 	 })
})
3、const init = async() => {
	const res =await getTableData()
	tableData.data = res.data
}
4、复选框的数据
//这个按钮是控制el-drawer的弹出
  <img width="28px" src="@/assets/icon/selection.png" @click="drawer = true" />
 //这是复选框的弹窗 可直接参考element-plus组件的内容
 <el-drawer v-model="drawer" title="列表显示设置" :direction="direction" :before-close="handleClose">
   <el-checkbox-group v-model="checkList" @change="checkboxChange" v-for="item in checkBoxData"
     :key="item.value">
     <el-checkbox :label="item.label" :value="item.label"></el-checkbox>
     </el-checkbox-group>
</el-drawer>
//复选框默认显示的数据
const checkList = ref(["物料编码", "产品类别", "编码有效期", "编码状态", "供货状态", "申请人", "申请日期", "流程环节"])
//tableData 数据
const tableData = reactive({
  key: new Date().getTime(),
  data: [],
  //这里是表格首次默认展示的数据,如果没有序号也可以直接赋值使用checkBoxData 的数据
  columnList: [
  //这里比checkBoxData 多了一个序号
    {
      label: '序号',
      prop: "",
      width: "60"
    },
    {
      label: '物料编码',
      prop: "imaterialCoded",
      width: "180"
    },
   ...
  ]
})
//复选框发生变化
const checkboxChange = () => {
   const arr = checkBoxData.filter((item) => { return checkList.value.some((i) => { return i == item.label }) })
  tableData.columnList = arr  //修改显示的列
}
const checkBoxData = reactive([
  {
    label: '物料编码',
    prop: "imaterialCoded",
    width: "180"
  },
  {
    label: '项目编码',
    prop: "projectCode",
    width: "180"
  },
 ...  //其他省略了
])

5、表格特殊数据的处理
<el-table-column show-overflow-tooltip :prop="item.prop" :label="item.label" :width="item.width">
   <template #default="scope">
    	<span v-if="item.label == '序号'" style="text-align:center;width:100%;display:inline-block">
                  {{ scope.$index+1 }}
         </span>
       <span v-if="item.label == '物料编码'">
          <a style="color: #1890ff; text-decoration: underline;cursor:pointer" @click="getInfo(scope.row.id)">{{ scope.row.materialCode }}
           </a>
       </span>
       <span v-else-if="item.label == '产品类别'">
           {{ scope.row.productType == 1 ? '标准件' : '定制件' }}
       </span>
        ...
       <span v-else>{{ scope.row[item.prop] }}</span>
    </template>
</el-table-column>

注意:tableData.columnList 可以设置默认值,不能设置为空,且复选框的数据格式(checkBoxData )要与columnList保持一致

相关推荐
刚刚好ā23 分钟前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
会发光的猪。3 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客3 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
周全全3 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
ZwaterZ4 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
码农六六4 小时前
vue3封装Element Plus table表格组件
javascript·vue.js·elementui
徐同保4 小时前
el-table 多选改成单选
javascript·vue.js·elementui
快乐小土豆~~4 小时前
el-input绑定点击回车事件意外触发页面刷新
javascript·vue.js·elementui
周三有雨4 小时前
【面试题系列Vue07】Vuex是什么?使用Vuex的好处有哪些?
前端·vue.js·面试·typescript
大霞上仙6 小时前
element ui table 每行不同状态
vue.js·ui·elementui