sortablejs 库
列表拖拽
<template>
<el-scrollbar height="500px">
<div id="draggableCard">
<el-card v-for="i in resultDate" :key="i">
{{ i }}
</el-card>
</div>
</el-scrollbar>
</template>
<script lang="ts" setup>
import {ref,onMounted} from 'vue'
import Sortable from "sortablejs";
const resultDate = ref([1,2,3,4,5]);
onMounted(() => {
Sortable.create(document.getElementById("draggableCard"), {
animation: 150,
onEnd: ({ newIndex, oldIndex }) => {
const currRow = resultDate.value.splice(oldIndex, 1);
resultDate.value.splice(newIndex, 0, currRow[0]);
},
});
});
</script>
双列表拖拽
<template>
<div>
<div class="flex">
<div class="list" ref="l1">
{{ list1 }}
<el-card v-for="(i, index) in list1" :key="i.label">
{{ index }}-{{ i.label }}
</el-card>
</div>
<div class="list" ref="l2">
{{ list2 }}
<el-card v-for="(i, index) in list2" :key="i.label">
{{ index }}-{{ i.label }}
</el-card>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Sortable from "sortablejs";
import { ref, reactive, onMounted } from "vue";
import { cloneDeep } from "lodash";
const list1 = reactive([
{
label: "姓名",
prop: "name",
},
{
label: "性别",
prop: "gender",
},
{
label: "年龄",
prop: "age",
},
{
label: "操作",
prop: "operation",
},
]);
const list2 = reactive([]);
const l1 = ref();
const l2 = ref();
onMounted(() => {
sortList();
});
const isMove = ref(true); // 判断是否移动
const sortList = () => {
Sortable.create(l1.value, {
group: { name: "card", pull: true, put: true },
onEnd({ newIndex, oldIndex }) {
if (isMove.value) {
const currRow = list1.splice(oldIndex, 1)[0];
list2.splice(newIndex, 0, currRow);
} else {
const currRow = list1.splice(oldIndex, 1)[0];
list1.splice(newIndex, 0, currRow);
}
},
onUpdate() {
isMove.value = false;
},
onMove() {
isMove.value = true;
},
});
Sortable.create(l2.value, {
group: { name: "card", pull: true, put: true },
onEnd({ newIndex, oldIndex }) {
if (isMove.value) {
const currRow = list2.splice(oldIndex, 1)[0];
list1.splice(newIndex, 0, currRow);
} else {
const currRow = list2.splice(oldIndex, 1)[0];
list2.splice(newIndex, 0, currRow);
}
},
onUpdate() {
isMove.value = false;
},
onMove() {
isMove.value = true;
},
});
};
// targetList 为空 奇怪
const dragOption = (name, currentList, targetList) => {
return {
group: { name, pull: true, put: true },
animation: 150,
onUpdate() {
isMove.value = false;
},
onMove() {
isMove.value = true;
},
onEnd: ({ newIndex, oldIndex }) => {
if (isMove.value) {
const currRow = currentList.splice(oldIndex, 1)[0];
targetList.splice(newIndex, 0, currRow);
} else {
const currRow = currentList.splice(oldIndex, 1)[0];
currentList.splice(newIndex, 0, currRow);
}
console.log("当前列表", currentList);
},
};
};
</script>
<style lang="scss" scoped>
.list {
height: 500px;
width: 300px;
border: 1px solid black;
}
</style>
表格拖拽
<template>
<div class="draggable" style="padding: 20px">
<el-table
row-key="id"
:data="state.tableData"
style="width: 100%"
>
<el-table-column
v-for="(item,index) in state.oldList"
:key="`col_${index}`"
:prop="state.newList[index].prop"
:label="item.label"
align="center"
>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import Sortable from 'sortablejs';
import { reactive, onMounted} from 'vue';
const state = reactive({
oldList: [],
newList: [],
tableData: [
{
id:1,
name:'李四',
gender:'男',
age:20,
},
{
id:2,
name:'王五',
gender:'未知',
age:18,
},
{
id:3,
name:'张三',
gender:'男',
age:22,
},
{
id:4,
name:'张三',
gender:'男',
age:22,
},
],
tableConfig: {
tableItems: [
{
label: '姓名',
prop: 'name',
},
{
label: '性别',
prop: 'gender',
},
{
label: '年龄',
prop: 'age',
},
]
}
})
// 行拖拽
const rowDrop = function () {
// 要拖拽元素的父容器
const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody');
Sortable.create(tbody, {
// 可被拖拽的子元素
draggable: ".draggable .el-table__row",
onEnd({newIndex, oldIndex}) {
const currRow = state.tableData.splice(oldIndex, 1)[0];
state.tableData.splice(newIndex, 0, currRow);
console.log('tableData',state.tableData);
}
});
}
// 列拖拽
const columnDrop = function() {
const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: evt => {
const oldItem = state.newList[evt.oldIndex];
state.newList.splice(evt.oldIndex, 1);
state.newList.splice(evt.newIndex, 0, oldItem);
}
});
}
onMounted(()=> {
state.oldList = JSON.parse(JSON.stringify(state.tableConfig.tableItems))
state.newList = JSON.parse(JSON.stringify(state.tableConfig.tableItems))
columnDrop()
rowDrop()
})
</script>
表格禁止拖拽到第一行
<template>
<div class="draggable" style="padding: 20px">
<el-table
:row-class-name="rowClassName"
row-key="id"
:data="state.tableData"
style="width: 100%"
>
<el-table-column
v-for="(item,index) in state.oldList"
:key="`col_${index}`"
:prop="state.newList[index].prop"
:label="item.label"
align="center"
>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import Sortable from 'sortablejs';
import { reactive, onMounted} from 'vue';
const state = reactive({
oldList: [],
newList: [],
tableData: [
{
id:1,
name:'李四',
gender:'男',
age:20,
},
{
id:2,
name:'王五',
gender:'未知',
age:18,
},
{
id:3,
name:'张三',
gender:'男',
age:22,
},
{
id:4,
name:'张三',
gender:'男',
age:22,
},
],
tableConfig: {
tableItems: [
{
label: '姓名',
prop: 'name',
},
{
label: '性别',
prop: 'gender',
},
{
label: '年龄',
prop: 'age',
},
]
}
})
const rowClassName = ({ row, rowIndex }) => {
// 为除了第一行外的所有行添加额外样式
return rowIndex !== 0 ? 'el-table__row__drag' : '';
}
// 行拖拽
const rowDrop = function () {
// 要拖拽元素的父容器
const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody');
Sortable.create(tbody, {
// 可被拖拽的子元素
draggable: ".draggable .el-table__row__drag", // 修改可拖拽元素
onEnd({newIndex, oldIndex}) {
const currRow = state.tableData.splice(oldIndex, 1)[0];
state.tableData.splice(newIndex, 0, currRow);
console.log('tableData',state.tableData);
}
});
}
// 列拖拽
const columnDrop = function() {
const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: evt => {
const oldItem = state.newList[evt.oldIndex];
state.newList.splice(evt.oldIndex, 1);
state.newList.splice(evt.newIndex, 0, oldItem);
}
});
}
onMounted(()=> {
state.oldList = JSON.parse(JSON.stringify(state.tableConfig.tableItems))
state.newList = JSON.parse(JSON.stringify(state.tableConfig.tableItems))
columnDrop()
rowDrop()
})
</script>
穿梭框拖拽
<template>
<div class="transfer" ref="transfer">
<el-transfer v-model="value" :data="data" :titles="titles">
<template #default="{ option }">
<div class="pannel-content">
<span :draggable="!option.disabled" @dragstart="drag($event, option)">{{
option.label
}}</span>
</div>
</template>
</el-transfer>
</div>
</template>
<script lang="ts" setup>
import Sortable from "sortablejs";
import { ref, onMounted} from "vue";
const data = ref([
{
key: 1,
label: `身份证取号`,
disabled: false,
},
{
key: 2,
label: `人脸取号`,
disabled: false,
},
{
key: 3,
label: `亮码取号`,
disabled: false,
},
{
key: 4,
label: `人证比对取号`,
disabled: false,
},
]);
const titles = ref(["待选列表", "已选列表"]);
const value = ref([] as any);
const draggingKey = ref(null as any);
const transfer = ref<HTMLDivElement | null>(null);
const drag = (ev: DragEvent, option: any) => {
draggingKey.value = option.key;
};
onMounted(() => {
const leftPanel = transfer?.value
?.getElementsByClassName("el-transfer-panel")[0]
.getElementsByClassName("el-transfer-panel__body")[0] as any;
const rightPanel = transfer?.value
?.getElementsByClassName("el-transfer-panel")[1]
.getElementsByClassName("el-transfer-panel__body")[0] as any;
const leftEl = leftPanel?.getElementsByClassName("el-transfer-panel__list")[0];
const rightEl = rightPanel?.getElementsByClassName("el-transfer-panel__list")[0];
Sortable.create(rightEl, {
onEnd: (evt: any) => {
const { oldIndex, newIndex } = evt;
const temp = value.value[oldIndex];
if (!temp || temp === "undefined") return; // 解决右边最后一项从右边拖左边,有undefined的问题
value.value[oldIndex] = value.value[newIndex];
value.value[newIndex] = temp;
},
});
Sortable.create(leftEl, {
onEnd: (evt: any) => {
const { oldIndex, newIndex } = evt;
if (oldIndex === newIndex) return;
const temp = data.value[oldIndex];
if (!temp || (temp as any) === "undefined") return; // 解决右边最后一项从右边拖左边,有undefined的问题
data.value[oldIndex] = data.value[newIndex];
data.value[newIndex] = temp;
},
});
leftPanel.ondragover = (ev: any) => {
ev.preventDefault();
};
leftPanel.ondrop = (ev: any) => {
ev.preventDefault();
const index = value.value.indexOf(draggingKey.value);
if (index !== -1) {
value.value.splice(index, 1);
}
};
rightPanel.ondragover = (ev: any) => {
ev.preventDefault();
};
rightPanel.ondrop = (ev: any) => {
ev.preventDefault();
if (value.value.indexOf(draggingKey.value) === -1) {
value.value.push(draggingKey.value);
}
};
});
</script>
<style scoped lang="scss">
:deep(.el-transfer__button) {
width: 30px;
}
</style>