拖拽总结
实现方式 | 特点 | 适用场景 |
---|---|---|
HTML5 原生拖拽 API | ✅ 直接使用 dataTransfer 进行数据传输✅ 兼容性好(大部分浏览器支持) ✅ 适合简单的拖拽场景 | 低代码平台、表单生成器、组件拖拽 |
Vue/React 组件库(如 Vue Draggable、SortableJS) | ✅ 提供更丰富的交互效果 ✅ 支持列表排序、拖拽嵌套 ❌ 依赖额外的库 | 复杂拖拽,如列表排序、树状结构 |
CSS 仅视觉拖拽(无交互) | ✅ 仅改变视觉位置,无数据交互 ❌ 无法存储拖拽数据 | 简单 UI 动画 |
目录
拖拽总结
HTML5 原生拖拽API(Drag and Drop API)
相关代码知识点:
e.dataTransfer.setData(format, data):
e.dataTransfer.effectAllowed = 'copy'; 设置拖拽的效果,表示拖拽的操作类型:
@dragover.prevent
@drop="onDropCanvas"
e.dataTransfer.getData('text/plain');:获取拖拽的数据(之前 dragstart 事件 setData 的数据)。
JSON.parse(itemData);:解析 JSON 数据,得到组件信息。
例子 —— 简易拖拽代码(H5: dataTransfer.setData + store 维护数据)
本例分析:
拖拽流程:
两种拖拽方式:
HTML5 原生拖拽API(Drag and Drop API)
分为:拖拽源 和 拖拽目标。适用于vue低代码开发。(若要 拖拽嵌套 或 复杂排序,考虑 Vue Draggable
(基于 SortableJS))
拖拽源 -> 拖拽开始(dragstart)
设置
dataTransfer.setData()
存储拖拽的数据。设置
effectAllowed
允许的拖拽行为。
draggable="true"
:启用 HTML5 拖拽。
@dragstart
触发onDragStart()
,存储数据。
e.dataTransfer.setData('text/plain', JSON.stringify(item))
让drop
端获取拖拽的数据。拖拽过程中(dragover)——(事件:
dragover,即
拖拽对象悬停在目标上时触发)
- 必须
preventDefault()
,否则drop
事件不会触发拖拽目标 -> 拖拽结束(drop)
读取
dataTransfer.getData()
获取拖拽的数据。在目标区域渲染组件。
@dragover.prevent
:阻止默认行为,允许drop
触发。(默认情况下,浏览器不允许drop)
@drop="onDropCanvas"
:处理组件释放到画布的逻辑。
e.dataTransfer.getData('text/plain')
读取拖拽的数据。
canvasComponents.value.push()
添加组件到画布。
相关代码知识点:
-
e.dataTransfer.setData(format, data)
:-
作用:设置拖拽时传输的数据,这样在
drop
事件时可以取回。 -
text/plain
:表示数据格式为纯文本字符串(不同浏览器可能要求必须是文本格式)。 -
JSON.stringify(item)
:将item
(对象)转换为字符串存储,方便drop
事件解析。
-
⚠ 注意:不设置 setData
,某些浏览器可能无法正确触发 drop
事件。
-
e.dataTransfer.effectAllowed = 'copy'; 设置拖拽的效果,表示拖拽的操作类型:
-
'copy'
:表示复制(不会影响原始数据)。 -
'move'
:表示移动(可能会删除原始数据)。 -
'link'
:表示创建链接。
-
-
@dragover.prevent
-
事件:
dragover
(拖拽对象悬停在目标上时触发)。 -
prevent
:阻止默认行为(默认情况下,浏览器不允许drop
)。
-
-
@drop="onDropCanvas"
-
事件:
drop
(用户松开鼠标时触发)。 -
作用:获取拖拽的数据;将组件添加到画布;更新 UI 状态。
-
-
e.preventDefault();
:避免浏览器默认行为(如打开文件)。 -
e.dataTransfer.getData('text/plain');
:获取拖拽的数据(之前dragstart
事件setData
的数据)。 -
JSON.parse(itemData);
:解析 JSON 数据,得到组件信息。 -
store.addComponentToCanvas(component);
:将组件添加到画布中。
例子 —— 简易拖拽代码(H5: dataTransfer.setData + store 维护数据)
<!-- test.vue --> <script setup> import e from 'cors'; import { store } from './store.js';const componentList = [{ id: 1, type: 'Container' },{ id: 2, type: 'Text'}, ]; // 拖拽开始事件 const onDragStart = (e, item) => {e.dataTransfer.setData('text/plain', JSON.stringify(item)); // 设置拖拽开始 传输的数据,纯文本 字符串,将 item 对象 转为字符串存储,便于后续drop解析e.dataTransfer.effectAllowed = 'copy'; // 拖拽效果,拖拽类型。copy 指 复制,不影响原数据;move,表 移动,可能会删原数据;link,表示创建链接store.setDragItem(item, true); // 记录当前正在拖拽的组件信息。true表示从组件库拖拽。(区分,从组件库 拖拽,和 画布内拖拽) } const onDropCanvas = () => {// const itemData = e.dataTransfer.getData('text/plain'); // 获取拖拽的数据// if(!itemData) return;// const item = JSON.parse(itemData); // 将字符串转为对象console.log("drop拖拽开始")store.dropToCanvas(null); } </script> <template><div class="app1"><h3>组件库(可拖动)</h3><div v-for="(item, index) in componentList":key="item.id"class="draggable-item"draggable="true"@dragstart="onDragStart($event, item)">{{ item.type }}</div><h3>画布区域</h3><div class="canvas"@dragover.prevent@drop="onDropCanvas"><!--@dropover.prevent 阻止默认行为。(默认情况下,浏览器不允许drop) --><div v-for="(item, index) in store.treeData" :key="item.id" class="draggable-item">{{ item.type }}-{{ item.id }}</div></div></div> </template> <style scoped lang='scss'> .app1 {padding: 20px;.draggable-item {border: 1px solid #ccc;text-align: center;width: 300px;height: 100px;line-height: 100px;background:pink;}.canvas {border: 2px dashed #ccc;width: 500px;height: 300px;margin-top:20px;// background: skyblue;} } </style>
// store.js import { reactive } from 'vue' export const store = reactive({treeData: [], // 画布中的组件数据dragItem: null, // 当前拖拽的组件isRawComponents: false, // 是否是组件库的// 设置当前拖拽的组件setDragItem(item, isRawComponents = false){this.dragItem = item;this.isRawComponents = isRawComponents;console.log("设置当前拖拽的组件。")},// 拖拽到画布中dropToCanvas() {if(!this.dragItem) return;const newItem = {id: Date.now(),type: this.dragItem.type,children: [], // 支持未来qiantao};this.treeData.push(newItem);console.log("拖拽到画布。")this.dragItem = null; // 清空拖拽数据} })
本例分析:
通过 全局
store
维护了拖拽数据,而不是使用dataTransfer.getData
来获取拖拽数据。
onDragStart
事件
当用户开始拖拽组件库中的组件时,会执行
onDragStart
方法。
onDragStart
里除了使用e.dataTransfer.setData
之外,还调用了store.setDragItem(item, true)
,这个方法的作用是在全局的 store 里记录当前拖拽的组件信息,并标记它是从组件库拖拽的(true
)。
onDropCanvas
事件
当拖拽到画布区域并触发
onDropCanvas
时,并没有使用e.dataTransfer.getData
获取数据。取而代之的是
store.dropToCanvas(null);
,这个方法直接从store
里获取之前存储的dragItem
并添加到treeData
里。
dropToCanvas
方法
dropToCanvas
方法检查this.dragItem
是否存在,如果存在,就创建一个新的newItem
并添加到treeData
里。这样,数据传递并没有通过
dataTransfer.getData
,而是通过全局store
变量来完成的。
拖拽流程:
onDragStart(e, item)
→store.setDragItem(item, true);
记录拖拽的组件数据。
onDropCanvas()
→store.dropToCanvas(null);
获取store.dragItem
并添加到treeData
里。
两种拖拽方式:
①dataTransfer.setData
和 getData
适用于不同的页面或应用之间的数据传递,但
②在同一个 Vue 组件的状态管理下,getData部分 完全可以使用 Vue 的 store
机制来管理拖拽数据。
②用 Vue 的
store
机制来管理拖拽数据的优势:
避免
dataTransfer.getData
只能存储字符串的限制,直接在store
里存储对象数据,不用手动JSON.stringify
和JSON.parse
。数据可以跨多个事件存储,即使拖拽过程中发生变化(比如鼠标移动到不同位置),仍然可以获取正确的数据。
更方便管理拖拽状态,比如可以在
store
里添加isDragging
状态,防止意外行为。
参考文献:
vue3 使用拖动插件vuedraggable@next - joken1310 - 博客园
Vue Draggable Next 安装和配置指南-CSDN博客
vue3使用拖拽组件draggable.next的使用教程【保姆级】_vue-draggable-next-CSDN博客
vue.draggable.next 中文文档 - itxst.com
https://github.com/SortableJS/vue.draggable.next
vue.draggable vue3例子
Vue-draggable-next 教程:轻松实现组件拖拽功能_慕课手记
vue3使用拖拽组件draggable.next的保姆级教程_vue.js_脚本之家