Files
Docker/WebVue/src/components/basic/DraggList.vue
T
2026-08-28 17:02:34 +08:00

164 lines
4.9 KiB
Vue

<template>
<div ref="draggableContainer" class="draggableContainer">
<main v-for="item in list" :key="item.title" style="margin:2px;">
<section class="draggable-item">
<section class="my-handle r-2"
style="width: 100%;display:flex;justify-content:space-between;line-height:32px;">
<div>
<a-input flex="none" readonly :value="item.sequence as number + 1" class="site-input-split" style="width: 40px;border-radius:0; border-top-left-radius: 5pt 5pt;
border-bottom-left-radius: 5pt 5pt; border-radius: 0;pointer-events: none" />
<a-input flex="none" readonly :value="item.title" class="site-input-split" style="width: 100px;border-radius:0; border-top-right-radius: 5pt 5pt;
border-bottom-right-radius: 5pt 5pt;pointer-events: none" />
</div>
<div style="margin-left: 4px;">
<a-radio-group v-model:value="item.hidden" @change="onChange">
<a-radio-button value="N">显示</a-radio-button>
<a-radio-button value="Y">隐藏</a-radio-button>
</a-radio-group>
</div>
<div style="margin-left: 4px;">
<a-input v-model:value="item.width" @change="onChange" style="width:60px; border-radius:0; border-top-left-radius: 5pt 5pt;
border-bottom-left-radius: 5pt 5pt; text-align: right;" />
<a-select style="width:60px; border-radius: 5pt 5pt;" v-model:value="item.fixed" @select="onChange">
<a-select-option value=""></a-select-option>
<a-select-option value="left">左</a-select-option>
<a-select-option value="right">右</a-select-option>
</a-select>
</div>
</section>
</section>
</main>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue';
import Sortable from 'sortablejs';
// interface Item {
// label: string;
// value: string; // 可能是会需要value值
// }
interface Props {
list: Array<Column>;
options?: Sortable.Options;
}
const draggableContainer = ref<HTMLDivElement | null>(null);
const props = defineProps<Props>();
interface EmitsType {
(e: 'update:list', value: any[]): void;
(e: 'onChangeList', value: any[]): void;
}
const emit = defineEmits<EmitsType>();
const sortable = ref<Sortable | null>(null);
onMounted(() => {
let i: number = 0;
props.list.forEach((element: Column) => {
element.sequence = i++;
});
initDraggable();
});
const onChange = () => {
emit('onChangeList', props.list);
};
const initDraggable = () => {
if (!draggableContainer.value) {
console.warn('容器不能为空');
return;
}
sortable.value = Sortable.create(draggableContainer.value, {
handle: '.my-handle',
chosenClass: 'chosen',
dragClass: 'drag',
direction: 'horizontal',
forceFallback: true,
animation: 300,
onUpdate(e: any) {
if (e.oldIndex !== undefined && e.newIndex !== undefined) {
// 删除拖拽的元素
let list = [...props.list];
const item = list.splice(e.oldIndex, 1)[0];
// 把删除的元素放到新的位置
list.splice(e.newIndex, 0, item);
let i: number = 0;
list = list.map((element: Column) => {
return { ...element, sequence: i++ };
});
emit('update:list', list);
emit('onChangeList', list);
};
},
...props.options
});
};
onUnmounted(() => {
sortable.value?.destroy();
});
</script>
<style lang="less" scoped>
.draggableContainer {
max-width: 30rem;
background: #ffffff;
color: #495057;
border: 0 none;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
.r-2 {
margin-right: 2rem;
}
.draggable-item {
margin: 0;
padding: 0.75rem 1.25rem;
border-width: 1px;
border-style: solid;
border-color: #d9d9d9;
color: #495057;
background: transparent;
transition: box-shadow 0.2s;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
font-weight: normal;
white-space: nowrap;
position: relative;
overflow: hidden;
}
//.draggable-item:hover {
// background: #e9ecef;
//}
.my-handle {
cursor: move;
cursor: -webkit-grabbing;
}
.drag {
// 正在拖拽中幽灵图的样式
display: none;
cursor: move;
cursor: -webkit-grabbing;
}
.chosen {
cursor: move;
cursor: -webkit-grabbing;
border-radius: 6px;
box-shadow: 0 2px 10px 0 rgb(0 0 0 / 20%);
}
</style>