Vue.Draggable使用nested-with-vmodel进行拖拽
1. 介绍
draggable是一个基于Sortable.js的Vue组件,用于实现拖拽功能。它支持触摸设备、拖拽和选择文本、智能滚动、不同列表之间的拖拽等功能,并且与Vue的视图模型同步刷新,兼容Vue2的过渡动画,支持撤销操作,并且可以与现有的UI组件兼容。
2. 官网地址
nested-with-vmodel拖拽
3. 安装
npm install vuedraggable
或者
pnpm install vuedraggable
4. NestedVmodel.vue组件
<script lang="ts">javascript">
import { defineComponent, PropType } from "vue";
import draggable from "vuedraggable";export default defineComponent({name: "NestedVmodel",components: {draggable},props: {list: {type: Array as PropType<Array<{ id: number; name: string; elements: Array<any> }>>,required: true}},emits: ["update:modelValue"],setup(props, { emit }) {const dragOptions = {animation: 200,group: "description",disabled: false,ghostClass: "ghost"};const emitter = (value: any) => {emit("update:modelValue", value);};const updateChildList = (parentId: number, updatedList: any) => {const updatedElements = props.list.map(el => {if (el.id === parentId) {return { ...el, elements: updatedList };}return el;});emitter(updatedElements);};const getUpdatedList = () => {return props.list;};return {dragOptions,emitter,updateChildList,getUpdatedList};}
});
</script>
<template><draggablev-bind="dragOptions"tag="div"class="item-container":list="list"item-key="id"@update:modelValue="emitter"><template #item="{ element }"><div :key="element.id" class="item-group"><div class="item">{{ element.name }}</div><nested-vmodelclass="item-sub":list="element.elements"@update:modelValue="updateChildList(element.id, $event)"/></div></template></draggable>
</template><style scoped lang="scss">
.item-container {box-sizing: border-box;max-width: 100%;padding: 0.75rem;margin: 0 auto;background-color: #f8f9fa;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;box-shadow: 0 4px 8px rgb(0 0 0 / 10%);
}.item-group {margin-bottom: 1rem;
}.item {padding: 0.5rem;cursor: pointer;background-color: #fff;border: 1px solid #ddd;border-radius: 6px;box-shadow: 0 2px 4px rgb(0 0 0 / 5%);transition: box-shadow 0.2s ease;
}.item:hover {box-shadow: 0 4px 8px rgb(0 0 0 / 10%);
}.item-sub {border-left: 2px dashed #bbb;
}.ghost {background-color: #e9ecef;opacity: 0.6;
}
</style>
5. 如何使用(示例代码)
<script lang="ts" setup>javascript">
import { ref, onMounted } from "vue";
import nestedVmodel from "@/components/ReTools/NestedVmodel.vue";// 拖拽列表数据
const dragList = ref([]);
const nestedTestRef = ref(null);// 获取数据逻辑
const getPromptGroup = async () => {// 获取数据的逻辑dragList.value = [{id: 4,name: "Lord Farquad",elements: []},{id: 1,name: "Shrek",elements: [{id: 5,name: "Prince Charming",elements: [{id: 3,name: "Donkey",elements: [{id: 2,name: "Fiona",elements: []}]}]}]}];
};const handleUpdate = newList => {dragList.value = newList;
};const getList = () => {if (nestedTestRef.value) {return nestedTestRef.value.getUpdatedList();}
};// 在组件挂载时加载数据
onMounted(async () => {if (dragList.value.length === 0) {await getPromptGroup();}
});
// 将 getList 方法暴露给父组件
defineExpose({getList
});
</script><template><nested-vmodelref="nestedTestRef":list="dragList"@update:modelValue="handleUpdate"/>
</template>
6. 页面效果(随意拖拽)
7. 弹窗打开获取数据
function openDraggableDialog(row?: ApiProps) {addDialog({title: "###",props: {},width: "40%",draggable: true,fullscreenIcon: true,closeOnClickModal: false,contentRenderer: () => h(draggable, { ref: draggableRef }),beforeSure: done => {if (draggableRef.value) {const updatedList = draggableRef.value.getList();}}});}