vue实现拖动div
实现拖动 Div 的基本思路
通过 Vue 的指令或组件封装,结合原生 DOM 事件(mousedown、mousemove、mouseup)实现拖动功能。核心逻辑是计算鼠标移动的偏移量,动态更新目标元素的定位样式(如 left 和 top)。
方法一:使用自定义指令
-
创建自定义指令
在 Vue 中注册一个全局或局部指令,监听目标元素的鼠标事件:Vue.directive('drag', { bind(el) { let isDragging = false; let offsetX, offsetY; el.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - el.getBoundingClientRect().left; offsetY = e.clientY - el.getBoundingClientRect().top; el.style.position = 'absolute'; // 确保元素可定位 }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; el.style.left = `${e.clientX - offsetX}px`; el.style.top = `${e.clientY - offsetY}px`; }); document.addEventListener('mouseup', () => { isDragging = false; }); } }); -
在模板中使用指令
通过v-drag指令绑定到目标元素:<template> <div v-drag class="draggable-div">拖拽我</div> </template>
方法二:封装为可复用组件
-
创建拖动组件
将逻辑封装为组件,通过props控制拖动行为:
export default { props: { initialPosition: { type: Object, default: () => ({ x: 0, y: 0 }) } }, data() { return { position: { ...this.initialPosition }, isDragging: false, offset: { x: 0, y: 0 } }; }, methods: { startDrag(e) { this.isDragging = true; this.offset.x = e.clientX - this.position.x; this.offset.y = e.clientY - this.position.y; }, onDrag(e) { if (!this.isDragging) return; this.position.x = e.clientX - this.offset.x; this.position.y = e.clientY - this.offset.y; }, stopDrag() { this.isDragging = false; } }, mounted() { document.addEventListener('mousemove', this.onDrag); document.addEventListener('mouseup', this.stopDrag); }, beforeDestroy() { document.removeEventListener('mousemove', this.onDrag); document.removeEventListener('mouseup', this.stopDrag); } }; -
在模板中使用组件
通过样式绑定动态更新位置:<template> <div class="draggable-component" :style="{ left: `${position.x}px`, top: `${position.y}px` }" @mousedown="startDrag" > 拖拽我 </div> </template>
方法三:使用第三方库
-
安装
vuedraggable库
适用于列表拖拽排序,但也可调整配置实现自由拖动:npm install vuedraggable -
配置自由拖动模式
通过draggable选项和 CSS 调整:
import draggable from 'vuedraggable'; export default { components: { draggable }, data() { return { list: [{ id: 1, text: '拖拽元素' }] }; } };<template> <draggable v-model="list" :options="{ group: 'free' }"> <div v-for="item in list" :key="item.id" class="draggable-item"> {{ item.text }} </div> </draggable> </template>
注意事项
-
性能优化
频繁的 DOM 操作可能影响性能,建议使用transform替代left/top:.draggable-div { transform: translate(0, 0); } -
边界限制
添加逻辑限制拖动范围,防止元素超出视口:onDrag(e) { const maxX = window.innerWidth - el.offsetWidth; const maxY = window.innerHeight - el.offsetHeight; this.position.x = Math.min(maxX, Math.max(0, e.clientX - this.offset.x)); this.position.y = Math.min(maxY, Math.max(0, e.clientY - this.offset.y)); } -
移动端支持
需额外监听touchstart、touchmove和touchend事件。






