实现Element UI中的el-table表格组件的行和列的拖拽排序
使用
Vue3 + Element Plus UI + sortablejs
安装sortablejs
pnpm install sortablejs
行拖拽
基本实现
效果
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";const tableData = ref([{id: 1,date: "2016-05-02",name: "王小虎111",age: 21,address: "上海市普陀区金沙江路 1518 弄",},{id: 2,date: "2016-05-04",name: "王小虎222",age: 22,address: "上海市普陀区金沙江路 1517 弄",},{id: 3,date: "2016-05-01",name: "王小虎333",age: 23,address: "上海市普陀区金沙江路 1519 弄",},{id: 4,date: "2016-05-03",name: "王小虎444",age: 24,address: "上海市普陀区金沙江路 1516 弄",},{id: 5,date: "2016-05-08",name: "王小虎555",age: 25,address: "上海市普陀区金沙江路 1518 弄",},
]);onMounted(() => {rowDrop();
});/*** 行拖拽排序*/
function rowDrop() {// 要侦听拖拽响应的DOM对象const tbody = document.querySelector(".el-table__body-wrapper tbody");const data = tableData.value;Sortable.create(tbody, {// handle: ".el-icon-rank",ghostClass: "target-row-class",// 结束拖拽后的回调函数onEnd({ newIndex, oldIndex }) {// 将oldIndex位置的数据删除并取出,oldIndex后面位置的数据会依次前移一位const currentRow = data.splice(oldIndex, 1)[0];// 将被删除元素插入到新位置(currRow表示上面的被删除数据)data.splice(newIndex, 0, currentRow);},});
}
</script><template><el-tableref="table":data="tableData"style="width: 100%"borderrow-key="id"><el-table-column prop="date" label="日期" /><el-table-column prop="name" label="姓名" /><el-table-column prop="age" label="年龄" /><el-table-column prop="address" label="地址" /><!--<el-table-column align="center" width="55">--><!-- <i class="el-icon-rank" />--><!--</el-table-column>--></el-table>
</template><style scoped lang="less">
.el-table {::v-deep {.target-row-class {background: #f0f9eb;}}
}
</style>
禁止某几行拖拽
效果
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";const tableData = ref([{id: 1,date: "2016-05-02",name: "王小虎111",age: 21,address: "上海市普陀区金沙江路 1518 弄",},{id: 2,date: "2016-05-04",name: "王小虎222",age: 22,address: "上海市普陀区金沙江路 1517 弄",},{id: 3,date: "2016-05-01",name: "王小虎333",age: 23,address: "上海市普陀区金沙江路 1519 弄",},{id: 4,date: "2016-05-03",name: "王小虎444",age: 24,address: "上海市普陀区金沙江路 1516 弄",},{id: 5,date: "2016-05-08",name: "王小虎555",age: 25,address: "上海市普陀区金沙江路 1518 弄",},
]);onMounted(() => {rowDrop();
});/*** 行拖拽排序*/
function rowDrop() {// 要侦听拖拽响应的DOM对象const tbody = document.querySelector(".el-table__body-wrapper tbody");const data = tableData.value;Sortable.create(tbody, {// handle: ".el-icon-rank",ghostClass: "target-row-class",// 匹配的元素将不会触发拖动filter: ".filtered",// 拖拽移动事件,返回false取消移动onMove: function ({ related }) {return related.className.indexOf("filtered") === -1;},// 结束拖拽后的回调函数onEnd({ newIndex, oldIndex }) {// 将oldIndex位置的数据删除并取出,oldIndex后面位置的数据会依次前移一位const currentRow = data.splice(oldIndex, 1)[0];// 将被删除元素插入到新位置(currRow表示上面的被删除数据)data.splice(newIndex, 0, currentRow);},});
}// 设置ID为1和5的行禁止拖拽
function tableRowClassName({ row, rowIndex }) {const freezeList = [1, 5];return freezeList.includes(row.id) ? "filtered" : "";
}
</script><template><el-tableref="table":data="tableData"style="width: 100%"borderrow-key="id":row-class-name="tableRowClassName"><el-table-column prop="date" label="日期" /><el-table-column prop="name" label="姓名" /><el-table-column prop="age" label="年龄" /><el-table-column prop="address" label="地址" /><!--<el-table-column align="center" width="55">--><!-- <i class="el-icon-rank" />--><!--</el-table-column>--></el-table>
</template><style scoped lang="less">
.el-table {::v-deep {.target-row-class {background: #f0f9eb;}// 禁止拖拽行背景色.filtered {background-color: #1db1e7 !important;}}
}
</style>
列拖拽
基本实现
效果
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";const columns = ref([{ label: "日期", prop: "date" },{ label: "姓名", prop: "name" },{ label: "年龄", prop: "age" },{ label: "地址", prop: "address" },
]);const tableData = ref([{id: 1,date: "2016-05-02",name: "王小虎111",age: 21,address: "上海市普陀区金沙江路 1518 弄",},{id: 2,date: "2016-05-04",name: "王小虎222",age: 22,address: "上海市普陀区金沙江路 1517 弄",},{id: 3,date: "2016-05-01",name: "王小虎333",age: 23,address: "上海市普陀区金沙江路 1519 弄",},{id: 4,date: "2016-05-03",name: "王小虎444",age: 24,address: "上海市普陀区金沙江路 1516 弄",},{id: 5,date: "2016-05-08",name: "王小虎555",age: 25,address: "上海市普陀区金沙江路 1518 弄",},
]);onMounted(() => {columnDrop();
});/*** 列拖拽排序*/
function columnDrop() {// 要侦听拖拽响应的DOM对象const wrapperTr = document.querySelector(".el-table__header-wrapper tr");Sortable.create(wrapperTr, {animation: 180,delay: 0,onEnd({ newIndex, oldIndex }) {const draggedItem = columns.value.splice(oldIndex, 1)[0];columns.value.splice(newIndex, 0, draggedItem);},});
}
</script><template><el-tableref="table":data="tableData"style="width: 100%"borderrow-key="id"><el-table-columnv-for="(column, index) in columns":key="index":prop="column.prop":label="column.label"/></el-table>
</template>
禁止某几行拖拽
效果
<script setup>
import { onMounted, ref } from "vue";
import Sortable from "sortablejs";const columns = ref([{ label: "日期", prop: "date" },{ label: "姓名", prop: "name", draggable: true },{ label: "年龄", prop: "age", draggable: true },{ label: "地址", prop: "address" },
]);const columnsDrop = ref([{ label: "日期", prop: "date" },{ label: "姓名", prop: "name" },{ label: "年龄", prop: "age" },{ label: "地址", prop: "address" },
]);const tableData = ref([{id: 1,date: "2016-05-02",name: "王小虎111",age: 21,address: "上海市普陀区金沙江路 1518 弄",},{id: 2,date: "2016-05-04",name: "王小虎222",age: 22,address: "上海市普陀区金沙江路 1517 弄",},{id: 3,date: "2016-05-01",name: "王小虎333",age: 23,address: "上海市普陀区金沙江路 1519 弄",},{id: 4,date: "2016-05-03",name: "王小虎444",age: 24,address: "上海市普陀区金沙江路 1516 弄",},{id: 5,date: "2016-05-08",name: "王小虎555",age: 25,address: "上海市普陀区金沙江路 1518 弄",},
]);// 定义变量来记录固定列的class名
const fixedColumnClass = "filtered";onMounted(() => {columnDrop();
});function setHeaderCellClass({ column }) {const columnLabels = columns.value.filter((column) => column.draggable).map((column) => column.label);return !columnLabels.includes(column.label) ? fixedColumnClass : "";
}/*** 列拖拽排序*/
function columnDrop() {// 要侦听拖拽响应的DOM对象const wrapperTr = document.querySelector(".el-table__header-wrapper tr");Sortable.create(wrapperTr, {animation: 180,delay: 0,ghostClass: "target-row-class",filter: `.${fixedColumnClass}`,// filter: (event, item) => {// // 也可以根据item的类名、id或其他属性来决定是否应该被排除// return !item.classList.contains("draggable");// },onMove: function ({ related }) {return related.className.indexOf(fixedColumnClass) === -1;},onEnd({ newIndex, oldIndex }) {const draggedItem = columnsDrop.value.splice(oldIndex, 1)[0];columnsDrop.value.splice(newIndex, 0, draggedItem);},});
}
</script><template><el-tableref="table":data="tableData"style="width: 100%"borderrow-key="id":header-cell-class-name="setHeaderCellClass"><el-table-columnv-for="(column, index) in columns":key="column.prop":prop="columnsDrop[index].prop":label="column.label"/></el-table>
</template><style scoped lang="less">
.el-table {::v-deep {.target-row-class {background: #f0f9eb;}.filtered {background-color: #1db1e7 !important;}}
}
</style>
封装Vue指令
未完待续