# HTML拖放API快速上手
最近在写一个网页拖放的小东西,一开始是以为要监听鼠标的点击移动和释放事件,后来查询发现不用那么麻烦,浏览器提供了内置的Drag 和 Drop API
# Grag & Drop
# 工作原理
给需要拖拽的元素添加以下代码:
<div
draggable="true"
ondrag="handleDrag"
/>
可放置区域(即接受拖拽元素的元素)
<div
ondragover="handleGragover"
ondrop="handleDrop"
/>
// 同时阻止默认的点击事件
// 原因:浏览器对默认的拖拽事件是禁止的
e.preventDefault()
# ondrag
拖拽开始
可存放拖拽数据,例如元素ID
# ondragover
进入放置区域
可进行更改样式等操作
# ondrop
元素放置时
对拖拽元素进行真实的移动
# Demo
实现一个简单的页面文件和元素的拖拽
# 实现效果
- 对于元素
- 对于图片
# 代码实现
HTML
<main> <div class="draggable-container"> <div id="draggable" class="draggable" draggable="true"></div> </div> <div id="droppable" class="droppable"></div> </main>
CSS
*{ box-sizing: border-box; padding: 0; margin: 0; } main{ width: 100vw; height: 100vh; display: grid; grid-template-columns: 1fr 1fr; place-items: center; background-color: hsl(0deg, 0%, 10%); } .draggable-container { width: 100%; height: 100%; display: grid; place-items: center; } .draggable, .droppable { border-radius: 4px; } .draggable { width: 25vw; height: 25vw; background-color: #00d9ff; } .droppable { width: 30vw; height: 30vw; border: 8px dashed #00d9ff; position: relative; display: grid; place-items: center; } .droppable::before { display: block; content: "请拖放到此区域"; position: absolute; color: white; font-family: sans-serif; font-size: 3vw; color: hsl(0, 0%, 30%); } .droppable img { width: 80%; height: 80%; object-fit: contain; } .dragover { border: 8px dashed #ffae00; } .dropped { border: 8px dashed #48ff00; } .dropped::before { z-index: -1; }
JS
const draggable = document.getElementById('draggable'); const droppable = document.getElementById('droppable'); draggable.addEventListener('dragstart', handleDragStart); droppable.addEventListener('dragover', handleDragover); droppable.addEventListener('dragleave', handleDragLeave); droppable.addEventListener('drop', handleDrop); function handleDragStart(e) { e.dataTransfer.setData('text/plain', e.target.id) } function handleDragover(e) { e.preventDefault(); droppable.classList.add('dragover'); } function handleDragLeave(e) { droppable.classList.remove('dragover') } function handleDrop(e) { e.preventDefault(); // 如果是文件 [ ...e.dataTransfer.items].forEach((item)=>{ if (item.kind === "file") { const file = item.getAsFile(); createPreview(file); } }) // 如果是元素 const draggedid = e.dataTransfer.getData("text/plain"); droppable.appendChild(document.getElementById(draggedid)); droppable.classList.add('dropped'); } function createPreview(imageFile) { if (!imageFile.type.startsWith("image/")) { return; } const image = document.createElement("img"); image.src = URL.createObjectURL(imageFile); image.onload = function() { URL.revokeObjectURL(this.src); } droppable.appendChild(image); }