为何首次拖拽轨道位置手柄时drag事件无法触发?
轨道位置栏手柄拖拽异常问题
我开发了一个JavaScript应用,实现轨道位置栏手柄的拖拽功能,让用户能跳转至音轨任意位置,但出现异常:首次拖拽时手柄无移动,drag事件也未触发,第二次拖拽才可正常生效。
相关代码
HTML部分
<div class="track-position-container"> <div class="position-bar"> <div class="completed-bar"></div> <div class="position-nob" ondrag="positionNobDragged(event)" ondragend="positionNobDragEnded(event)"></div> </div> </div>
JavaScript部分
function positionNobDragged(event) { const positionBar = document.querySelector('.position-bar'); const positionNob = document.querySelector('.position-nob'); const completedBar = document.querySelector('.completed-bar'); const x = event.x - positionBar.offsetLeft; positionNob.style.left = x; completedBar.style.width = completedBar.style.left + x; } function positionNobDragEnded(event) { positionNobDragged(event); }
问题原因
- 原生
drag事件依赖dragstart事件触发才能正常工作,你只绑定了drag和dragend,首次拖拽时缺少dragstart的触发,导致后续drag事件无法激活;第二次拖拽时浏览器默认行为或元素状态变化间接触发了dragstart,才让事件正常运行。 - 代码存在样式赋值错误:
positionNob.style.left = x未添加单位px,样式无法生效completedBar.style.width = completedBar.style.left + x逻辑错误,completedBar.style.left为空字符串,拼接后会生成无效值
修复方案
方案一:补全原生拖拽事件流程
给元素添加dragstart事件绑定,并完成原生拖拽的必要步骤:
<div class="track-position-container"> <div class="position-bar"> <div class="completed-bar"></div> <div class="position-nob" ondragstart="positionNobDragStarted(event)" ondrag="positionNobDragged(event)" ondragend="positionNobDragEnded(event)"></div> </div> </div>
function positionNobDragStarted(event) { // 必须设置dataTransfer,否则部分浏览器不会触发后续拖拽事件 event.dataTransfer.setData('text/plain', ''); } function positionNobDragged(event) { const positionBar = document.querySelector('.position-bar'); const positionNob = document.querySelector('.position-nob'); const completedBar = document.querySelector('.completed-bar'); const barRect = positionBar.getBoundingClientRect(); // 限制拖拽范围在轨道栏内 let x = event.clientX - barRect.left; x = Math.max(0, Math.min(x, barRect.width)); positionNob.style.left = `${x}px`; completedBar.style.width = `${x}px`; } function positionNobDragEnded(event) { positionNobDragged(event); }
方案二:使用鼠标事件实现拖拽(更推荐)
原生拖拽有诸多限制,用mousedown+mousemove+mouseup组合更灵活,无需修改HTML:
const positionNob = document.querySelector('.position-nob'); const positionBar = document.querySelector('.position-bar'); const completedBar = document.querySelector('.completed-bar'); let isDragging = false; positionNob.addEventListener('mousedown', (e) => { isDragging = true; e.preventDefault(); // 阻止默认行为,避免选中文字干扰 }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const barRect = positionBar.getBoundingClientRect(); let x = e.clientX - barRect.left; x = Math.max(0, Math.min(x, barRect.width)); positionNob.style.left = `${x}px`; completedBar.style.width = `${x}px`; }); document.addEventListener('mouseup', () => { isDragging = false; });
内容的提问来源于stack exchange,提问作者gib65
相关产品推荐
相关产品推荐

