vue拖拽布局实现方案
Vue 拖拽布局实现方案
使用第三方库(推荐)
Vue.Draggable 是一个基于 Sortable.js 的 Vue 组件,适用于列表拖拽排序和布局调整。安装后可直接在模板中使用,支持跨列表拖拽、动画效果和自定义拖拽手柄。
npm install vuedraggable
<template>
<draggable v-model="list" group="items" @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>
原生 HTML5 拖拽 API
通过 HTML5 的 draggable 属性和 Vue 事件绑定实现基础拖拽功能。需要手动处理拖拽状态和数据更新,适合简单场景。

<template>
<div
v-for="item in list"
:key="item.id"
draggable="true"
@dragstart="handleDragStart($event, item)"
@dragover.prevent
@drop="handleDrop($event, item)"
>
{{ item.name }}
</div>
</template>
<script>
export default {
data() {
return {
list: [...],
draggedItem: null
};
},
methods: {
handleDragStart(e, item) {
this.draggedItem = item;
e.dataTransfer.effectAllowed = 'move';
},
handleDrop(e, targetItem) {
const index = this.list.indexOf(this.draggedItem);
this.list.splice(index, 1);
const targetIndex = this.list.indexOf(targetItem);
this.list.splice(targetIndex, 0, this.draggedItem);
}
}
};
</script>
网格布局拖拽(如 Grid Layout)
vue-grid-layout 专为响应式网格拖拽设计,支持栅格化布局和动态调整尺寸。适用于仪表盘等复杂场景。

npm install vue-grid-layout
<template>
<grid-layout
:layout.sync="layout"
:col-num="12"
:row-height="30"
:is-draggable="true"
>
<grid-item v-for="item in layout" :key="item.i" :x="item.x" :y="item.y" :w="item.w" :h="item.h">
{{ item.i }}
</grid-item>
</grid-layout>
</template>
<script>
import { GridLayout, GridItem } from 'vue-grid-layout';
export default {
components: { GridLayout, GridItem },
data() {
return {
layout: [
{ x: 0, y: 0, w: 2, h: 2, i: '0' },
{ x: 2, y: 0, w: 2, h: 4, i: '1' }
]
};
}
};
</script>
拖拽性能优化
对于大型列表,使用 v-for 时应结合 key 和虚拟滚动(如 vue-virtual-scroller)。避免直接操作 DOM,通过 Vue 的响应式数据驱动视图更新。
自定义拖拽逻辑
通过监听 touchstart/mousedown、touchmove/mousemove 和 touchend/mouseup 事件,计算元素位移并动态修改样式。需注意移动端兼容性和事件冒泡处理。
methods: {
startDrag(e) {
this.initialX = e.clientX - this.$el.getBoundingClientRect().left;
this.initialY = e.clientY - this.$el.getBoundingClientRect().top;
document.addEventListener('mousemove', this.drag);
document.addEventListener('mouseup', this.endDrag);
},
drag(e) {
this.$el.style.left = `${e.clientX - this.initialX}px`;
this.$el.style.top = `${e.clientY - this.initialY}px`;
},
endDrag() {
document.removeEventListener('mousemove', this.drag);
document.removeEventListener('mouseup', this.endDrag);
}
}






