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保持一致

相关推荐
王解16 分钟前
Vue CLI 脚手架创建项目流程详解 (2)
前端·javascript·vue.js
刘大浪19 分钟前
vue.js滑动到顶便锁定位置
前端·javascript·vue.js
ordinary901 小时前
指令-v-for的key
前端·javascript·vue.js
武昌库里写JAVA2 小时前
使用React Strict DOM改善React生态系统
数据结构·vue.js·spring boot·算法·课程设计
devotemyself2 小时前
vue的ElMessage的css样式不生效
前端·css·vue.js
Mr。轩。2 小时前
Vue 单表 CRUD模板 前端
前端·javascript·vue.js
小码快撩3 小时前
vue应用移动端访问缓慢问题
前端·javascript·vue.js
海绵波波1074 小时前
Gin-vue-admin(2):项目初始化
vue.js·golang·gin
海绵波波1074 小时前
Gin-vue-admin(4):项目创建前端一级页面和二级页面
前端·vue.js·gin