<textarea>不能作为文件拖拽目标,必须用<div>等容器并同时监听dragenter、dragover(均需preventDefault())和drop事件,从e.dataTransfer.files读取文件;容器须有尺寸且无pointer-events:none。
<textarea> 本身不能作为文件拖拽上传的目标区域,它不是合法的 drop 目标,也不参与 HTML5 拖放流程。所以“在 <textarea> 上阻止默认事件来接收大文件”这个思路从根源上就不可行。
真正能接收拖拽文件的是普通容器元素(如 <div>),且必须满足几个硬性条件。下面直接说清楚怎么做、为什么不能用 <textarea>,以及如何安全替代:
<div id="drop-area" class="drop-area"><p>拖拽文件到这里(支持大文件)</p><input type="file" id="file-input" multiple style="display: none;"></div>
<textarea> 不响应 dragover/drop 事件,浏览器会忽略你在它上面绑定的这些监听器;<div> 等块级容器才是标准拖拽目标,只要正确阻止默认行为,就能稳定捕获文件。dragenter 和 dragover 都要调用 e.preventDefault()
只在 drop 里阻止已经晚了。浏览器在 dragover 阶段就决定是否允许投放,不阻止就直接打开/下载文件。
const dropArea = document.getElementById('drop-area');['dragenter', 'dragover', 'dragleave'].forEach(type => {dropArea.addEventListener(type, e => e.preventDefault(), false);});
drop 事件中读取文件必须用 e.dataTransfer.files
不是 e.target.files(那是 <input type="file"> 的),也不是 e.dataTransfer.items(兼容性差):
dropArea.addEventListener('drop', e => {e.preventDefault();const files = Array.from(e.dataTransfer.files); // FileList → 数组console.log('收到', files.length, '个文件,总大小:', files.reduce((sum, f) => sum + f.size, 0));});
确保容器有实际尺寸和可交互状态
如果 <div> 没内容、没高度、或被 pointer-events: none 覆盖,dragover 根本不会触发——鼠标“进不去”。
.drop-area {min-height: 120px;border: 2px dashed #999;padding: 20px;text-align: center;}
dataTransfer 接口;draggable="true" 或监听 drop,事件也不会冒泡到它身上,更不会触发 dataTransfer.files;<textarea> 的拖拽逻辑只限于“拖入文字片段”,不是文件。<input type="file">,但保留它用于点击选择;<div> 时手动触发 file-input.click();dragenter 时加 .drag-over 类),提升反馈感;fetch 或 XMLHttpRequest 层逻辑。不复杂但容易忽略