Vanilla JavaScript拖拽功能二次拖拽失效问题求助
拖拽功能首次正常后续失效问题解决
问题描述
使用Vanilla JavaScript实现Web应用拖拽功能,需求是将元素拖放后移动到div内的新位置,但遇到以下问题:
- 首次拖放操作正常,后续无法再次进行拖放
- 调试发现:首次拖拽元素时无内联样式(见附录A);第二次拖拽时元素已带有内联样式(见附录B),且无法修改这些样式值
- 手动为可拖拽元素添加内联样式后,首次拖放也会失效
代码(省略非必要部分)
JavaScript
const list = document.querySelector("#list"); const rect = list.getBoundingClientRect(); let oldLeft, oldTop, mouseXStart, mouseYStart; function dragStart(event) { event.dataTransfer.setData("plain/text", event.target.id); const item = document.querySelector("#" + event.target.id); mouseXStart = event.clientX - rect.left; mouseYStart = event.clientY - rect.top; oldLeft = item.style.left; oldTop = item.style.top; console.log(item); } function dragOver(event) { event.preventDefault(); event.dataTransfer.dropEffect = "move"; } function dropItem(event) { event.preventDefault(); const mouseXEnd = event.clientX - rect.left; const mouseYEnd = event.clientY - rect.top; //Calculate by how much mouse has been moved const newLeft = mouseXEnd - mouseXStart; const newTop = mouseYEnd - mouseYStart; const item = document.querySelector('#' + event.dataTransfer.getData("plain/text")); item.style.left = oldLeft + newLeft + "px"; item.style.top = oldTop + newTop + "px"; }
CSS
#list { position: relative; top: 60px; height: 600px; width: 100%; border: 2px solid rgb(107, 14, 14); display: block; } #list>div { position: absolute; height: 200px; width: 200px; background-color: blue; margin: 10px; overflow: hidden; text-align: left; }
HTML
<div id="list" ondrop="dropItem(event)" ondragover="dragOver(event)"> <div id="test" draggable="true" ondragstart="dragStart(event)"> <button type="button"></button> <div> <p>Test</p> </div> </div> </div>
附录
附录A:首次调用dragStart()时console.log()输出
<div id="test" draggable="true" ondragstart="dragStart(event)">
附录B:第二次调用dragStart()时console.log()输出
<div id="test" draggable="true" ondragstart="dragStart(event)" style="left: 853px; top: 147px;">
问题原因与解决方法
核心问题
- 样式值拼接错误:首次拖拽时
item.style.left为空字符串,拼接后生成有效CSS值;第二次拖拽时item.style.left是带px的字符串,与数字拼接会生成类似"853px100"的无效值,浏览器无法识别,导致元素位置无法更新。 - 容器位置未实时获取:页面加载时只计算一次
list的位置,若页面滚动或容器移动,会导致拖拽计算偏差。
修复步骤
- 将样式值转为数字计算,空值默认取0;
- 在拖拽开始和结束时实时获取容器位置;
- 用元素
dataset存储旧位置,避免全局变量污染。
修复后的代码
const list = document.querySelector("#list"); let mouseXStart, mouseYStart; function dragStart(event) { event.dataTransfer.setData("plain/text", event.target.id); const item = document.querySelector("#" + event.target.id); // 实时获取容器位置 const rect = list.getBoundingClientRect(); mouseXStart = event.clientX - rect.left; mouseYStart = event.clientY - rect.top; // 将样式值转为数字,空值默认0,存储到元素dataset中 item.dataset.oldLeft = parseInt(item.style.left) || 0; item.dataset.oldTop = parseInt(item.style.top) || 0; console.log(item); } function dragOver(event) { event.preventDefault(); event.dataTransfer.dropEffect = "move"; } function dropItem(event) { event.preventDefault(); // 实时获取容器位置 const rect = list.getBoundingClientRect(); const mouseXEnd = event.clientX - rect.left; const mouseYEnd = event.clientY - rect.top; const newLeft = mouseXEnd - mouseXStart; const newTop = mouseYEnd - mouseYStart; const item = document.querySelector('#' + event.dataTransfer.getData("plain/text")); // 取出存储的旧位置进行数字计算 const oldLeft = parseInt(item.dataset.oldLeft); const oldTop = parseInt(item.dataset.oldTop); item.style.left = (oldLeft + newLeft) + "px"; item.style.top = (oldTop + newTop) + "px"; }
内容的提问来源于stack exchange,提问作者terasss2
相关产品推荐
相关产品推荐

