vue 实现拖动
Vue 实现拖动功能
使用 HTML5 原生拖放 API
在 Vue 中可以通过 HTML5 的拖放 API 实现基本的拖动功能。需要监听 dragstart、dragover 和 drop 事件。
<template>
<div
@dragstart="handleDragStart"
@dragover.prevent
@drop="handleDrop"
draggable="true"
>
拖动元素
</div>
</template>
<script>
export default {
methods: {
handleDragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id)
},
handleDrop(e) {
const id = e.dataTransfer.getData('text/plain')
const draggableElement = document.getElementById(id)
e.target.appendChild(draggableElement)
}
}
}
</script>
使用第三方库 vue-draggable
对于更复杂的拖动场景,推荐使用 vue-draggable 库。它基于 Sortable.js,提供了丰富的拖动功能。
安装:
npm install vuedraggable
使用:
<template>
<draggable v-model="list" @end="onDragEnd">
<div v-for="item in list" :key="item.id">
{{ item.name }}
</div>
</draggable>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: { draggable },
data() {
return {
list: [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
]
}
},
methods: {
onDragEnd() {
console.log('拖动结束')
}
}
}
</script>
自定义拖动指令
可以创建自定义指令来实现更灵活的拖动控制。
Vue.directive('drag', {
bind(el, binding) {
let startX, startY, initialX, initialY
el.style.position = 'absolute'
el.addEventListener('mousedown', (e) => {
startX = e.clientX
startY = e.clientY
initialX = el.offsetLeft
initialY = el.offsetTop
document.addEventListener('mousemove', move)
document.addEventListener('mouseup', up)
e.preventDefault()
})
function move(e) {
const dx = e.clientX - startX
const dy = e.clientY - startY
el.style.left = initialX + dx + 'px'
el.style.top = initialY + dy + 'px'
}
function up() {
document.removeEventListener('mousemove', move)
document.removeEventListener('mouseup', up)
}
}
})
拖动排序实现
结合 Vue 的响应式特性,可以实现拖动排序功能。
<template>
<div
v-for="(item, index) in items"
:key="item.id"
draggable="true"
@dragstart="dragStart(index)"
@dragover.prevent
@dragenter="dragEnter(index)"
@dragend="dragEnd"
>
{{ item.text }}
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' }
],
draggingIndex: null
}
},
methods: {
dragStart(index) {
this.draggingIndex = index
},
dragEnter(index) {
if (this.draggingIndex !== index) {
const temp = this.items[this.draggingIndex]
this.$set(this.items, this.draggingIndex, this.items[index])
this.$set(this.items, index, temp)
this.draggingIndex = index
}
},
dragEnd() {
this.draggingIndex = null
}
}
}
</script>
拖动边界限制
可以通过计算限制拖动元素的移动范围。
function move(e) {
const dx = e.clientX - startX
const dy = e.clientY - startY
let newX = initialX + dx
let newY = initialY + dy
// 限制在父容器内
const parentRect = el.parentElement.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
newX = Math.max(0, Math.min(newX, parentRect.width - elRect.width))
newY = Math.max(0, Math.min(newY, parentRect.height - elRect.height))
el.style.left = newX + 'px'
el.style.top = newY + 'px'
}
拖动性能优化
对于大量可拖动元素,应该使用事件委托来优化性能。
mounted() {
this.$refs.container.addEventListener('mousedown', (e) => {
if (e.target.classList.contains('draggable')) {
// 拖动逻辑
}
})
}
触摸屏支持
为支持移动设备,需要添加触摸事件处理。
el.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX
startY = e.touches[0].clientY
// 其他逻辑类似鼠标事件
})
以上方法可以根据具体需求选择使用,从简单的原生 API 到功能完善的第三方库,Vue 提供了多种实现拖动功能的方案。







