模拟deepseek拖拽上传
开发过程中可能会遇到两个疑问:为什么绑定drop 事件后上传不了或者浏览器会直接打开拖拽的文件?为什么将拖拽的元素放在dragleave绑定的模块子元素上时dragleave事件会被反复触发?此篇文章都有解决

首先我们来了解下可能需要使用到的拖拽事件:
【dragenter事件】将元素拖拽到目标区域时触发
【dragover事件】 将元素拖拽到目标区域时(每几百毫秒)触发一次。
【dragleave事件】 进入目标区域后将拖拽的元素移出目标区域时触发。
【dragend 事件】 在拖放操作结束时触发(通过释放鼠标按钮或单击 escape 键)。
【drop 事件】将拖拽的元素放在目标区域时触发。
tips:这里要注意为确保
drop事件始终按预期触发,应当在处理dragover事件的代码部分始终包含preventDefault()调用。
要实现deepseek的拖拽上传效果,首先我们得有一个外层区域去绑定dragenter事件来获取我们将元素拖拽到目标元素的动作,在
- 在外层区域去绑定
dragenter事件来获取我们将元素拖拽到目标区域的动作 - 拖拽入目标区域后将之前位置的元素背景设置模糊【filter:blur(3px)】同时显示上传结构
- 给上传结构绑定【
dragleave事件】来获取拖拽元素离开目标区域的动作 - 给上传结构绑定【
drop.prevent】来获取用户在目标区域放下元素的动作,这里必须调用preventDefault()来阻止浏览器弹出选择文件的弹窗 - 为了让drop事件正常触发,必须在上传结构上绑定一个【
dragover.prevent】 - 使用e.dataTransfer.files来获取拖拽操作中的数据
tips:
bug:由于我们目标区域的内部还有一些文字和图片结构,当将拖拽的元素移入我们目标元素内部的图片/文字这些子元素上时,会触发该目标元素绑定的dragleave事件
原因:从技术上讲,拖动元素确实暂时离开了外层
div的边界,即使它仍然在外层div的可视区域内。这是因为事件冒泡和拖放目标的边界检测是基于元素的边框进行的。解决方案:可以检查
event.relatedTarget属性来确定离开的目标。如果离开的目标是div的一个子元素,则可能不需要执行任何操作。
具体实现:
<template>
<div>
<div
class="questionArea"
@dragenter.prevent.stop="isDrag = true"
:style="{ filter: isDrag ? 'blur(3px)' : 'none' }"
>
<div class="questionInput">
<el-input
v-model="sendValue"
resize="none"
maxlength="5000"
type="textarea"
/>
</div>
</div>
<div class="sendGroup flex">
<!-- 附件上传按钮 -->
<div class="connectContainer" @click="handleClickUpload">
<el-tooltip placement="top" :show-after="200" :hide-after="0"
><template #content>
上传附件(仅识别文字)<br />
最多50个,每个100MB,支持各类文档和图片</template
>
<svg-icon icon-class="attachment"
/></el-tooltip>
</div>
<!-- 发送 -->
<el-button type="primary" color="#006eff" round size="large"
>发送
</el-button>
</div>
<!-- 拖拽上传区域 -->
<div
v-show="isDrag"
class="drag-upload-demo flex"
@dragleave.prevent.stop="handleDragLeave"
@dragover.prevent.stop
@drop.prevent.stop="handleDragUpload"
>
<el-icon class="el-icon--upload" size="50px" color="#a8abb2">
<upload-filled />
</el-icon>
<div class="text">文件拖拽到此处即可上传</div>
</div>
<!-- 点击上传file -->
<input
class="deepseeek-upload"
name="file"
multiple
:accept="accept"
type="file"
@change="
($event) => {
filesChange(Array.from($event.target.files)); //获取点击的文件信息
}
"
style="display: none"
/>
</div>
</template>
<script setup>
const isDrag = ref(false);
const sendValue = ref("");
const accept =
".doc,.docx,xls,xlsx,.pdf,.ppt,.pptx,.txt,.html,.js,.css,.png,.jpg,.jpeg,.bmp,.tiff,.tif";
// 移出拖拽区域
const handleDragLeave = (e) => {
let demoDom = document.querySelector(".drag-upload-demo");
// 这里要单独判断 鼠标移出的区域是否属于我们外层绑定drag的dom之外
!demoDom.contains(e.relatedTarget) && (isDrag.value = false);
};
// 通过拖拽上传文件
const handleDragUpload = (e) => {
isDrag.value = false;
// 这里可以通过e.dataTransfer.files来获取到拖拽的文件列表
// filesChange(Array.from(e.dataTransfer.files));
};
// 通过点击按钮上传文件
const handleClickUpload = () => {
document.querySelector(".deepseeek-upload").click();
};
const filesChange = (files) => {
// 这里写你的上传方法,files就是拖拽上传/点击按钮选中的文件
};
</script>
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)