vue实现弹窗拖拽排序
Vue 实现弹窗拖拽排序
使用 Vue.Draggable 库
安装 Vue.Draggable 库:
npm install vuedraggable
在组件中引入并使用:
<template>
<div>
<draggable v-model="dialogList" @end="onDragEnd">
<div v-for="dialog in dialogList" :key="dialog.id" class="dialog-item">
{{ dialog.title }}
</div>
</draggable>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: { draggable },
data() {
return {
dialogList: [
{ id: 1, title: 'Dialog 1' },
{ id: 2, title: 'Dialog 2' },
{ id: 3, title: 'Dialog 3' }
]
}
},
methods: {
onDragEnd() {
console.log('New order:', this.dialogList)
}
}
}
</script>
<style>
.dialog-item {
padding: 10px;
margin: 5px;
background: #f0f0f0;
cursor: move;
}
</style>
自定义拖拽实现
通过 HTML5 的拖放 API 实现:
<template>
<div>
<div
v-for="dialog in dialogList"
:key="dialog.id"
class="dialog-item"
draggable="true"
@dragstart="handleDragStart($event, dialog.id)"
@dragover.prevent
@drop="handleDrop($event, dialog.id)"
>
{{ dialog.title }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
dialogList: [
{ id: 1, title: 'Dialog 1' },
{ id: 2, title: 'Dialog 2' },
{ id: 3, title: 'Dialog 3' }
],
draggedItemId: null
}
},
methods: {
handleDragStart(event, id) {
this.draggedItemId = id
event.dataTransfer.effectAllowed = 'move'
},
handleDrop(event, targetId) {
const draggedIndex = this.dialogList.findIndex(item => item.id === this.draggedItemId)
const targetIndex = this.dialogList.findIndex(item => item.id === targetId)
if (draggedIndex !== -1 && targetIndex !== -1) {
const newList = [...this.dialogList]
const [removed] = newList.splice(draggedIndex, 1)
newList.splice(targetIndex, 0, removed)
this.dialogList = newList
}
}
}
}
</script>
结合弹窗组件实现
在弹窗组件中添加拖拽功能:
<template>
<div>
<button @click="showDialog = true">Show Dialog</button>
<div v-if="showDialog" class="dialog-wrapper" ref="dialog">
<div class="dialog-header" @mousedown="startDrag">
Drag Me
<button @click="showDialog = false">Close</button>
</div>
<div class="dialog-content">
Dialog Content
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
showDialog: false,
isDragging: false,
startX: 0,
startY: 0,
startLeft: 0,
startTop: 0
}
},
methods: {
startDrag(e) {
this.isDragging = true
this.startX = e.clientX
this.startY = e.clientY
const dialog = this.$refs.dialog
this.startLeft = dialog.offsetLeft
this.startTop = dialog.offsetTop
document.addEventListener('mousemove', this.handleDrag)
document.addEventListener('mouseup', this.stopDrag)
},
handleDrag(e) {
if (!this.isDragging) return
const dialog = this.$refs.dialog
const dx = e.clientX - this.startX
const dy = e.clientY - this.startY
dialog.style.left = `${this.startLeft + dx}px`
dialog.style.top = `${this.startTop + dy}px`
},
stopDrag() {
this.isDragging = false
document.removeEventListener('mousemove', this.handleDrag)
document.removeEventListener('mouseup', this.stopDrag)
}
}
}
</script>
<style>
.dialog-wrapper {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 300px;
border: 1px solid #ccc;
background: white;
z-index: 1000;
}
.dialog-header {
padding: 10px;
background: #f0f0f0;
cursor: move;
display: flex;
justify-content: space-between;
}
.dialog-content {
padding: 15px;
}
</style>
注意事项
确保拖拽元素设置了正确的 CSS 定位属性(如 position: absolute 或 position: fixed)
对于复杂的拖拽场景,考虑使用第三方库如 interact.js 或 sortablejs
移动端支持需要额外处理 touch 事件
拖拽性能优化:对于大量元素,使用虚拟滚动等技术







