跳至主要內容

vxe-table v4 结合 Sortable 实现拖拽排序

Azil大约 2 分钟

需求简介

  • 表格带多选框并可全选
  • 表格支持手动拖拽排序
  • 可选项:实时获取最新的顺序

代码风格依照 jsrun.net 编写,如需融入项目请自行调整。

最终效果

点击预览open in new window

实现过程

复现官方示例拖拽效果并添加多选框

如果不需要实时获取最新的顺序,可忽略后续过程直接使用下面的代码即可

<vxe-table
  ref="tableRef"
  border
  :scroll-y="{enabled: false}"
  :row-config="{
    useKey: true,
    isHover: true,
  }"
  :checkbox-config="{
    strict: true,
    range: true,
    trigger: 'row',
    highlight: true,
  }"
  @checkbox-change="handleSelectionChange"
  @checkbox-all="handleSelectionChange"
  @checkbox-range-end="handleSelectionChange"
  :data="tableData"
>
  <vxe-column width="60">
    <template #header>
      <vxe-tooltip content="按住后可以上下拖动排序!" enterable>
        <i class="vxe-icon-question-circle-fill"></i>
      </vxe-tooltip>
    </template>
    <template #default>
      <span class="drag-btn">
        <i class="vxe-icon-edit"></i>
      </span>
    </template>
  </vxe-column>
  <vxe-column type="checkbox" width="55" fixed="left"></vxe-column>
  <vxe-column field="id" title="主键"></vxe-column>
  <vxe-column field="name" title="Name"></vxe-column>
</vxe-table>

<button type="button" @click="submit">获取已选项</button>
var Main = {
    data () {
        return {
            tableData: [],
            ids: [],
        }
    },
    mounted () {
        this.init();
    },
    methods: {
        submit() {
            // 由于 vxe-table 默认勾选项排序是按用户的点击顺序排列,需要手动处理一下
            const ids = this.getIds();
            console.log(ids);
        },
        handleSelectionChange({ records }) {
            // TODO: 如果无需实时获取,可删除此方法
            this.ids = this.getIds(records);
        },
        getIds(checkboxRecords = []) {
            if (checkboxRecords.length === 0) { return []; }
            const tableIds = this.tableData.map(item => item.id);
            let list = checkboxRecords;
            const newIds = tableIds.filter(id => {
            return list.find(fid => fid == id);
            });
            return newIds;
        },
        init() {
            var list = []
            for(var index = 0; index < 3; index++){
                list.push({
                    id: index + 1,
                    name: 'test' + index,
                })
            }
            this.tableData = list
            this.$nextTick(() => {
                this.rowDrop();
            })
            this.ids = [];
        },
        rowDrop() {
            if (this.sortable1) {
                this.sortable1.destroy();
                this.sortable1 = false;
            }
            const $table = this.$refs.tableRef
            this.sortable1 = Sortable.create($table.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
                handle: '.drag-btn',
                animation: 300,
                ghostClass: "ghost",
                onEnd: ({newIndex, oldIndex}) => {
                    const currRow = this.tableData.splice(oldIndex, 1)[0]
                    this.tableData.splice(newIndex, 0, currRow)
                }
            })
        }
    },
    destroyed() { // 销毁
        if (this.sortable1) {
            this.sortable1.destroy();
            this.sortable1 = false;
        }
    }
};

Vue.createApp(Main).use(VXETable).mount('#app')

错误方法

当时的想法是,每当手动拖拽排序后,从已勾选的列表中找到对换位置的项更换一下位置就行。 但是出现下面这种情况时,勾选项与表格显示项就异常混乱

用户不按表格顺序勾选,比如先勾选第五行再勾选第一行。 可以在上面在线预览内容放开测试

rowDrop() {
    if (this.sortable1) {
        this.sortable1.destroy();
        this.sortable1 = false;
    }
    const $table = this.$refs.tableRef
    this.sortable1 = Sortable.create($table.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
        handle: '.drag-btn',
        animation: 300,
        ghostClass: "ghost",
        onEnd: ({newIndex, oldIndex}) => {
            // TODO: 实时获取排序的错误方法
            const newId = this.tableData[newIndex].id;
            const oldId = this.tableData[oldIndex].id;
            const findNewId = this.ids.findIndex(item => item == newId);
            const findOldId = this.ids.findIndex(item => item == oldId);
            if (findNewId != -1 && findOldId != -1) {
                const currRowId = this.ids.splice(findOldId, 1)[0];
                this.ids.splice(findNewId, 0, currRowId);
            }
            const currRow = this.tableData.splice(oldIndex, 1)[0]
            this.tableData.splice(newIndex, 0, currRow)
        }
    })
}

正确方法

rowDrop() {
    if (this.sortable1) {
        this.sortable1.destroy();
        this.sortable1 = false;
    }
    const $table = this.$refs.tableRef
    this.sortable1 = Sortable.create($table.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
        handle: '.drag-btn',
        animation: 300,
        ghostClass: "ghost",
        onEnd: ({newIndex, oldIndex}) => {
            const currRow = this.tableData.splice(oldIndex, 1)[0]
            this.tableData.splice(newIndex, 0, currRow);

            // TODO: 实时获取排序的正确方法
            const tableIds = this.tableData.map(item => item.id);
            const newIds = tableIds.filter(id => {
                return this.ids.find(fid => fid == id);
            });
            this.ids = newIds;
        }
    })
}
上次编辑于:
贡献者: Azil