ElementuiPlus的table组件实现行拖动与列拖动

借助了插件sortablejs。这种方法只适合做非树状table。如果想实现树状table,并且可拖动。可以试一下aggridVue3这个插件

javascript 复制代码
<template>
  <div class="draggable" style="padding: 20px">
    <el-table row-key="id" :data="tableData" style="width: 100%">
      <el-table-column v-for="(item, index) in oldList" :key="`col_${index}`" :prop="newList[index].prop"
        :label="item.label" align="center">
      </el-table-column>
    </el-table>
  </div>
</template>

<script setup lang="ts">
import Sortable from 'sortablejs'
import { onMounted, ref } from 'vue'

// 只适合做平级的table行和列拖动

const oldList = ref()
const newList = ref()

// 表头
const tableItems = ref([
  {
    label: '姓名',
    prop: 'name',
  },
  {
    label: '性别',
    prop: 'gender',
  },
  {
    label: '年龄',
    prop: 'age',
  },
])

// 表体数据
const tableData = ref(
  [
    {
      id: 1,
      name: '李四',
      gender: '男',
      age: 20,
    },
    {
      id: 2,
      name: '王五',
      gender: '未知',
      age: 18,
    },
    {
      id: 3,
      name: '张三',
      gender: '男',
      age: 22,
    },
  ]
)

// 行拖拽
const rowDrop = function () {
  // 要拖拽元素的父容器 tbody
  const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody')
  Sortable.create(tbody, {
    //  可被拖拽的子元素
    draggable: ".draggable .el-table__row",
    onEnd({ newIndex, oldIndex }) {
      // newIndex 拖动到的新的索引
      // oldIndex 没拖动前的索引
      const currRow = tableData.value.splice(oldIndex, 1)[0]
      tableData.value.splice(newIndex, 0, currRow)
    }
  });
}

// 列拖拽
const columnDrop = function () {
  // 要拖拽元素的父容器 头部的tr
  const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
  Sortable.create(wrapperTr, {
    animation: 180,
    delay: 0,
    onEnd: (evt: any) => {
      const oldItem = newList.value[evt.oldIndex];
      newList.value.splice(evt.oldIndex, 1);
      newList.value.splice(evt.newIndex, 0, oldItem);
    }
  })
}

onMounted(() => {
  oldList.value = JSON.parse(JSON.stringify(tableItems.value))
  newList.value = JSON.parse(JSON.stringify(tableItems.value))
  columnDrop()
  rowDrop()
})
</script>

效果如下

我试了加操作列,通过el-table-column的默认插槽进行实现,但是列拖动的时候,操作列的内容一直在最后一列,并没有跟着移动

代码如下,如果不需要列拖动的话,可以采取这种方式

javascript 复制代码
<template>
  <div class="draggable" style="padding: 20px">
    <el-table row-key="id" :data="tableData" style="width: 100%">
      <el-table-column v-for="(item, index) in oldList" :key="`col_${index}`"
        :label="item.label" align="center">
        <template #default="{ row, column, $index }">
          <div v-if="column.label !== '操作'">
            {{ row[newList[index].prop] }}
          </div>
          <div v-else>
            <el-button size="small">操作</el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script setup lang="ts">
import Sortable from 'sortablejs'
import { onMounted, ref } from 'vue'

// 只适合做平级的table行和列拖动

const oldList = ref()
const newList = ref()

// 表头
const tableItems = ref([
  {
    label: '姓名',
    prop: 'name',
  },
  {
    label: '性别',
    prop: 'gender',
  },
  {
    label: '年龄',
    prop: 'age',
  },
  {
    label: '操作',
    prop: 'operate',
  },
])

// 表体数据
const tableData = ref(
  [
    {
      id: 1,
      name: '李四',
      gender: '男',
      age: 20,
    },
    {
      id: 2,
      name: '王五',
      gender: '未知',
      age: 18,
    },
    {
      id: 3,
      name: '张三',
      gender: '男',
      age: 22,
    },
  ]
)

// 行拖拽
const rowDrop = function () {
  // 要拖拽元素的父容器 tbody
  const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody')
  Sortable.create(tbody, {
    //  可被拖拽的子元素
    draggable: ".draggable .el-table__row",
    onEnd({ newIndex, oldIndex }) {
      // newIndex 拖动到的新的索引
      // oldIndex 没拖动前的索引
      const currRow = tableData.value.splice(oldIndex, 1)[0]
      tableData.value.splice(newIndex, 0, currRow)
    }
  });
}

// 列拖拽
const columnDrop = function () {
  // 要拖拽元素的父容器 头部的tr
  const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
  Sortable.create(wrapperTr, {
    animation: 180,
    delay: 0,
    onEnd: (evt: any) => {
      const oldItem = newList.value[evt.oldIndex];
      newList.value.splice(evt.oldIndex, 1);
      newList.value.splice(evt.newIndex, 0, oldItem);
    }
  })
}

onMounted(() => {
  oldList.value = JSON.parse(JSON.stringify(tableItems.value))
  newList.value = JSON.parse(JSON.stringify(tableItems.value))
  columnDrop()
  rowDrop()
})
</script>

还有一种解决办法就是,把操作放到弹窗操作,比如双击某一行的时候,弹出弹窗,传入这行的数据,在弹窗里面进行操作,这样就不需要添加操作内一列了。行拖动和列拖动也都能使用

相关推荐
长风清留扬33 分钟前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
m0_748247801 小时前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营1 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood2 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
joan_852 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特2 小时前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
Watermelo6173 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
一个处女座的程序猿O(∩_∩)O5 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
燃先生._.11 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js