Bootstrap

VUE3+elementPlus 表格动态列+原生JS拖拽

先介绍下原生JS的drag事件:

需要手动开启draggable="true"

ondrag

该事件在元素正在拖动时触发

ondrag 事件在元素或者选取的文本被拖动时触发。

提示: 链接和图片默认是可拖动的,不需要 draggable 属性。

  • ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件
  • ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
  • ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件
  • ondrop - 在一个拖动过程中,释放鼠标键时触发此事件
  • 释放目标时触发的事件:
  • ondragend - 用户完成元素拖动后触发
  • ondrag - 元素正在拖动时触发
  • ondragstart - 用户开始拖动元素时触发
  • 在拖动目标上触发事件 (源元素):

ondragend

该事件在用户完成元素的拖动时触发

 

ondragstart

该事件在用户开始拖动元素时触发

 

ondragenter

该事件在拖动的元素进入放置目标时触发

ondragenter 事件在拖动的元素或选择的文本进入到有效的放置目标时触发。

ondragenter 和 ondragleave 事件可以帮助用户更好的理解可拖动元素进入和离开放置区域的过程。 你可以在可拖动元素进入和离开放置区域时设置不同的背景颜色。

ondragleave

该事件在拖动元素离开放置目标时触发

ondragleave 事件在可拖动的元素或选取的文本移出放置目标时执触发。

ondragenter 和 ondragleave 事件可以帮助用户更好的理解可拖动元素进入和离开放置区域的过程。 你可以在可拖动元素进入和离开放置区域时设置不同的背景颜色。

ondragover

该事件在拖动元素在放置目标上时触发

ondragover 事件在可拖动元素或选取的文本正在拖动到放置目标时触发。

默认情况下,数据/元素不能放置到其他元素中。 如果要实现改功能,我们需要防止元素的默认处理方法。我们可以通过调用 event.preventDefault() 方法来实现 ondragover 事件。

ondrop

该事件在拖动元素放置在目标区域时触发

ondrop 事件在可拖动元素或选取的文本放置在目标区域时触发。

需要注意拷贝重置数组,列表渲染的数组也要隔离开,不然一选择都会跟着变. 

 数据源于:https://blog.csdn.net/qq_36384657/article/details/128667410

 全部源码:

<template>
  <div>
    <div style="width=300px;float: left; margin-bottom: 10px;">
      <el-button type="primary" @click="visible = true">字段配置</el-button>
    </div>
    <el-popover
      :visible="visible"
      placement="bottom"
      trigger="click"
      title="自定义展示列表"
      width="200"
      virtual-triggering>
      <el-checkbox
        style="width: 120px"
        v-for="(item, index) in cloumns"
        v-model="item.visible"
        :key="item.prop"
        :label="item.label"
        :draggable="true"
        @dragstart="dragStartFn(index)"
        @dragenter="dragEnterFn($event, index)"
        @dragover="dragoverFn($event, index)" />
      <el-divider style="margin: 10px 0" />
      <div style="width: 135px; margin: 0 auto">
        <el-button @click="reset">重置</el-button>
        <el-button type="primary" @click="confirm">确定</el-button>
      </div>
    </el-popover>
    <div>
      <el-table
        :data="tableData"
        style="width: 100%"
        border
        :tree-props="{ children: 'children' }"
        ref="table">
        <el-table-column
          v-for="(item, index) in cloumnsCOM"
          :prop="item.prop"
          :label="item.label"
          :key="index" />
      </el-table>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onBeforeMount } from "vue";
//多选框绑定数据
const cloumns = ref([
  { label: "计划名称", prop: "planName", visible: true },
  { label: "编号", prop: "id", visible: true },
  { label: "计划开始日期", prop: "beginTimeP", visible: true },
  { label: "计划完成日期", prop: "endTimeP", visible: true },
  { label: "实际开始日期", prop: "beginTimeS", visible: true },
  { label: "实际完成日期", prop: "endTimeS", visible: true },
  { label: "状态", prop: "status", visible: false },
  { label: "逾期状态", prop: "delayStatus", visible: false },
  { label: "备注", prop: "remark", visible: false },
]);
const tableData = ref([
  {
    id: "001",
    planName: "ffff",
    beginTimeP: "2022-02-03",
    endTimeP: "2022-02-03",
    beginTimeS: "2022-02-03",
    endTimeS: "2022-02-03",
    children: [
      {
        id: "00101",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
      {
        id: "00102",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
      {
        id: "00103",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
      {
        id: "00104",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
    ],
  },
  {
    id: "002",
    planName: "uuuu",
    beginTimeP: "2022-02-03",
    endTimeP: "2022-02-03",
    beginTimeS: "2022-02-03",
    endTimeS: "2022-02-03",
    children: [
      {
        id: "00201",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
      {
        id: "00202",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
    ],
  },
  {
    id: "003",
    planName: "yyyy",
    beginTimeP: "2022-02-03",
    endTimeP: "2022-02-03",
    beginTimeS: "2022-02-03",
    endTimeS: "2022-02-03",
    children: [
      {
        id: "00301",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
      {
        id: "00302",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
    ],
  },
  {
    id: "004",
    planName: "xxxx",
    beginTimeP: "2022-02-03",
    endTimeP: "2022-02-03",
    beginTimeS: "2022-02-03",
    endTimeS: "2022-02-03",
    children: [
      {
        id: "00401",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
      {
        id: "00402",
        planName: "ffff",
        beginTimeP: "2022-02-03",
        endTimeP: "2022-02-03",
        beginTimeS: "2022-02-03",
        endTimeS: "2022-02-03",
      },
    ],
  },
]);
// 重置数据
const reCloumns = ref([]);
//列表渲染数据深拷贝
const tempCloumns = ref([]);
const cloumnsCOM = computed(() => {
  return (tempCloumns.value as any).filter((item) => item.visible);
});
onBeforeMount(() => {
  tempCloumns.value = JSON.parse(JSON.stringify(cloumns.value));
  reCloumns.value = JSON.parse(JSON.stringify(cloumns.value));
});
const visible = ref(false);
// 拖动
const dragIndex = ref(0);
const enterIndex = ref(0);
const dragStartFn = (index: number) => {
  dragIndex.value = index;
};
const dragEnterFn = (e: any, index: number) => {
  e.preventDefault();
  enterIndex.value = index;
  const source = cloumns.value[dragIndex.value];
  cloumns.value.splice(dragIndex.value, 1);
  cloumns.value.splice(index, 0, source);
  dragIndex.value = index;
};
const dragoverFn = (e: any, index: number) => {
  e.preventDefault();
};
const confirm = () => {
  tempCloumns.value = JSON.parse(JSON.stringify(cloumns.value));
  visible.value = false;
};
const reset = () => {
  cloumns.value = JSON.parse(JSON.stringify(reCloumns.value));
  tempCloumns.value = JSON.parse(JSON.stringify(reCloumns.value));
  visible.value = false;
};
</script>

;