关于preventDefault函数的异常行为疑问
关于dragstart事件中preventDefault影响子元素拖拽的问题解释
问题描述
对preventDefault的工作机制存在困惑:在示例中,给elem2的dragstart事件监听添加event.preventDefault()后,elem2无法拖拽符合预期,但拖拽elem3时,它的拖拽事件也被取消了——明明elem3的事件处理器里并没有调用preventDefault。
补充背景:拖拽可拖拽元素时,dragstart事件会在目标元素及其所有祖先元素上触发。此处事件捕获设为false,事件按elem3→elem2→elem1的顺序冒泡。未添加preventDefault时三个元素都可拖拽,添加后elem3也失效,原因不明。
核心原因
dragstart事件的默认行为是启动整个拖拽操作,只要事件传播路径(捕获/冒泡阶段)上的任意一个事件监听器调用了preventDefault(),整个拖拽操作就会被取消,不管这个监听器属于目标元素还是祖先元素。
当拖拽elem3时:
- 事件先在elem3触发,其处理器未阻止默认行为;
- 事件冒泡到elem2,这里的处理器调用了
preventDefault(),直接取消了拖拽的默认启动行为; - 最终整个拖拽操作无法启动,elem3的拖拽自然失效。
解决方法
如果需要实现「elem2不能拖拽,但elem3可以拖拽」的效果,只需在elem2的事件处理器中判断事件的目标是否为elem2本身,仅当目标是elem2时才阻止默认行为:
function elem2EventHandler(event) { console.log("target: " + event.target.id); console.log("currentTarget: " + event.currentTarget.id); // 仅当触发事件的目标是elem2自身时,阻止拖拽启动 if (event.target === event.currentTarget) { event.preventDefault(); } }
完整代码示例
JavaScript
const elem1 = document.getElementById("elem1"); elem1.addEventListener("dragstart", elem1EventHandler, false); const elem2 = document.getElementById("elem2"); elem2.addEventListener("dragstart", elem2EventHandler, false); const elem3 = document.getElementById("elem3"); elem3.addEventListener("dragstart", elem3EventHandler, false); function elem1EventHandler(event) { console.log("target: " + event.target.id); console.log("currentTarget: " + event.currentTarget.id); } function elem2EventHandler(event) { console.log("target: " + event.target.id); console.log("currentTarget: " + event.currentTarget.id); if (event.target === event.currentTarget) { event.preventDefault(); } } function elem3EventHandler(event) { console.log("target: " + event.target.id); console.log("currentTarget: " + event.currentTarget.id); }
CSS
#elem1 { display: block; position: relative; width: 200px; height: 150px; background-color: deepskyblue; } #elem2 { display: block; width: 150px; height: 100px; background-color: greenyellow; } #elem3 { display: block; width: 100px; height: 50px; background-color: coral }
HTML
<div id="elem1" draggable="true"> <div id="elem2" draggable="true"> <div id="elem3" draggable="true"> </div> </div> </div>
内容的提问来源于stack exchange,提问作者Dante
相关产品推荐
相关产品推荐

