|
@@ -0,0 +1,189 @@
|
|
|
|
+<template>
|
|
|
|
+ <table class="table table-tiny drag-table">
|
|
|
|
+ <colgroup>
|
|
|
|
+ <col width="20" />
|
|
|
|
+ <col v-for="column in columns" :key="column.prop" :width="column.width" />
|
|
|
|
+ </colgroup>
|
|
|
|
+ <thead>
|
|
|
|
+ <tr>
|
|
|
|
+ <th></th>
|
|
|
|
+ <th v-for="column in columns" :key="column.prop">
|
|
|
|
+ {{ column.label }}
|
|
|
|
+ </th>
|
|
|
|
+ </tr>
|
|
|
|
+ </thead>
|
|
|
|
+ <tbody
|
|
|
|
+ class="drag-table-tbody"
|
|
|
|
+ @drop.prevent="dropInnerElement"
|
|
|
|
+ @dragover.prevent="dragOver($event)"
|
|
|
|
+ @dragleave.prevent
|
|
|
|
+ >
|
|
|
|
+ <tr
|
|
|
|
+ v-for="row in tableData"
|
|
|
|
+ :key="row.$key"
|
|
|
|
+ :id="row.$key"
|
|
|
|
+ :class="[
|
|
|
|
+ 'drag-table-row',
|
|
|
|
+ {
|
|
|
|
+ 'after-drop': row.$key === curDropRow.$key && isDragDown,
|
|
|
|
+ 'before-drop': row.$key === curDropRow.$key && !isDragDown,
|
|
|
|
+ },
|
|
|
|
+ ]"
|
|
|
|
+ draggable="false"
|
|
|
|
+ @dragstart="($event) => dragStart($event, row)"
|
|
|
|
+ @dragend.prevent="dragEnd"
|
|
|
|
+ >
|
|
|
|
+ <td
|
|
|
|
+ class="drag-handle"
|
|
|
|
+ @mousedown.stop="dragHandleMousedown"
|
|
|
|
+ @mouseup.stop="dragHandleMouseup"
|
|
|
|
+ >
|
|
|
|
+ <div class="drag-handle">1</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td v-for="column in columns" :key="column.prop">
|
|
|
|
+ <slot :name="column.prop" v-bind:row="row">
|
|
|
|
+ {{ row[column.prop] }}
|
|
|
|
+ </slot>
|
|
|
|
+ </td>
|
|
|
|
+ </tr>
|
|
|
|
+ </tbody>
|
|
|
|
+ </table>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import { randomCode } from "@/plugins/utils";
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ name: "drag-table",
|
|
|
|
+ props: {
|
|
|
|
+ data: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default() {
|
|
|
|
+ return [];
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ columns: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default() {
|
|
|
|
+ // {label,prop,width?}[]
|
|
|
|
+ return [];
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ sortField: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: "sortNum",
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ tableData: [],
|
|
|
|
+ curDragRow: {},
|
|
|
|
+ curDropRow: {},
|
|
|
|
+ dragStartPageY: null,
|
|
|
|
+ isDragDown: false,
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ buildData(val) {
|
|
|
|
+ if (!val) {
|
|
|
|
+ this.tableData = [];
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.tableData = val.map((item) => {
|
|
|
|
+ return {
|
|
|
|
+ ...item,
|
|
|
|
+ $key: randomCode(),
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ getRelateElement(dom) {
|
|
|
|
+ let element = null;
|
|
|
|
+ let parentNode = dom;
|
|
|
|
+ while (!element && !parentNode.className.includes("drag-table-tbody")) {
|
|
|
|
+ if (!element && parentNode["id"]) {
|
|
|
|
+ element = parentNode;
|
|
|
|
+ } else {
|
|
|
|
+ parentNode = parentNode.parentNode;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return element;
|
|
|
|
+ },
|
|
|
|
+ getSiblingRow(targetKey, offset) {
|
|
|
|
+ const pos = this.tableData.findIndex((row) => row.$key === targetKey);
|
|
|
|
+ return this.tableData[pos + offset] || null;
|
|
|
|
+ },
|
|
|
|
+ dragStart(e, row) {
|
|
|
|
+ this.dragStartPageY = e.pageY;
|
|
|
|
+ this.curDragRow = row;
|
|
|
|
+ },
|
|
|
|
+ dragOver(e) {
|
|
|
|
+ // console.log(e.target);
|
|
|
|
+ this.isDragDown = e.pageY > this.dragStartPageY;
|
|
|
|
+ if (e.target.className.includes("drag-table-tbody")) {
|
|
|
|
+ this.curDropRow = this.isDragDown
|
|
|
|
+ ? this.tableData.slice(-1)[0]
|
|
|
|
+ : this.tableData[0];
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const elementDom = this.getRelateElement(e.target);
|
|
|
|
+ if (!elementDom) return;
|
|
|
|
+
|
|
|
|
+ const targetKey = elementDom.id;
|
|
|
|
+ this.curDropRow = this.getSiblingRow(targetKey, 0);
|
|
|
|
+ },
|
|
|
|
+ dropInnerElement() {
|
|
|
|
+ // console.log(this.curDragRow.id, this.curDropRowId);
|
|
|
|
+ if (this.curDragRow.id === this.curDropRow.id || !this.curDropRow) return;
|
|
|
|
+
|
|
|
|
+ // 往下:target上一个位置
|
|
|
|
+ // 往上:target下一个位置
|
|
|
|
+ this.moveElementToElement({
|
|
|
|
+ curRow: this.curDragRow,
|
|
|
|
+ toRow: this.curDropRow,
|
|
|
|
+ isDragDown: this.isDragDown,
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ dragEnd(e) {
|
|
|
|
+ e.target.setAttribute("draggable", false);
|
|
|
|
+ this.curDragRow = {};
|
|
|
|
+ this.curDropRow = {};
|
|
|
|
+ this.dragStartPageY = null;
|
|
|
|
+ this.isDragDown = false;
|
|
|
|
+ },
|
|
|
|
+ moveElementToElement({ curRow, toRow, isDragDown }) {
|
|
|
|
+ const curPos = this.tableData.findIndex(
|
|
|
|
+ (row) => row.$key === curRow.$key
|
|
|
|
+ );
|
|
|
|
+ this.tableData.splice(curPos, 1);
|
|
|
|
+
|
|
|
|
+ const toPos = this.tableData.findIndex((row) => row.$key === toRow.$key);
|
|
|
|
+ const offset = isDragDown ? 1 : 0;
|
|
|
|
+ this.tableData.splice(toPos + offset, 0, curRow);
|
|
|
|
+
|
|
|
|
+ this.tableData.forEach((row, index) => {
|
|
|
|
+ row[this.sortField] = index + 1;
|
|
|
|
+ });
|
|
|
|
+ this.$emit("sort-change", this.tableData);
|
|
|
|
+ },
|
|
|
|
+ dragHandleMousedown(e) {
|
|
|
|
+ const elementDom = this.getRelateElement(e.target);
|
|
|
|
+ elementDom.setAttribute("draggable", true);
|
|
|
|
+ },
|
|
|
|
+ dragHandleMouseup(e) {
|
|
|
|
+ const elementDom = this.getRelateElement(e.target);
|
|
|
|
+ elementDom.setAttribute("draggable", false);
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ data: {
|
|
|
|
+ handler(val) {
|
|
|
|
+ this.buildData(val);
|
|
|
|
+ },
|
|
|
|
+ immediate: true,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+</script>
|