Rob*_*ski 2 html javascript drag-and-drop dom-events event-capturing
我试图让我的拖放工作在JavaScript中正常工作,而不必显式扫描父元素或其他ID,类循环和其他hacky魔术.
现在,当我拖动元素池中的一个元素并将其拖动到灰色区域时,该元素将被复制到放置区域(到目前为止一切正确).我基本上复制拖动元素的HTML,清除放置区域(目标)并向其添加新元素.
当您在放置区中已经有一些子元素并将其拖到子元素上时,问题就开始了.然后drop事件中的目标是子元素,而不是附加事件的div.这会导致拖动的元素清除并将其自身复制到子项而不是drop容器中.
预期的结果应该是,无论是将它放在子节点上还是直接放在主放置容器上,目标应始终是父节点,因为我正在使用事件捕获模式.
这是我在JS Fiddle中的示例代码.我正在使用带捕获的事件监听器,但它似乎正在进行冒泡阶段而忽略了捕获阶段.为什么?
这样做的正确方法是什么?
function onDrag(ev) {
var el = ev.target;
//console.log("Drag: " + ev.target.outerHTML)
ev.dataTransfer.setData('text/html', ev.target.outerHTML);
}
function onContainerOver(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move"
}
function onContainerDrop(ev) {
ev.preventDefault();
//console.log("Drop: " + ev.dataTransfer.getData("text/html"))
ev.target.innerHTML = ev.dataTransfer.getData("text/html");
}
document.getElementById('target').addEventListener('drop', onContainerDrop, true); // This should not bubble, but it does. Target is always the child first rather than the element where the event listener resides. Why???Run Code Online (Sandbox Code Playgroud)
#list {}
.el {
padding: 5px;
margin: 10px;
border: solid 1px black;
background-color: #86d4ff;
cursor: move;
line-height: 1em;
text-align: left;
}
#target {
min-height: 200px;
width: 100%;
background-color: #ffdea6;
border: 1px dashed gray;
text-align: center;
line-height: 100px;
}Run Code Online (Sandbox Code Playgroud)
<div id="list">
<div class="el" draggable="true" ondragstart="onDrag(event)">ELEMENT A</div>
<div class="el" draggable="true" ondragstart="onDrag(event)">ELEMENT B</div>
<div class="el" draggable="true" ondragstart="onDrag(event)">ELEMENT C</div>
</div>
<div id="target" ondragover="onContainerOver(event)">
Drop Here
</div>Run Code Online (Sandbox Code Playgroud)
当您在子元素上放置任何内容或者在子元素上发生任何事件时,事件目标始终是子元素,因为这是事件发生的位置.这是目标.
???????????????????????????????????????
? ?????????????????????????? ?
? ? Child [Target] ? ?
? ?????????????????????????? ?
? Parent ?
???????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
然后,此事件作为子元素传递给子元素的事件处理程序,同时作为Target和CurrentTarget
???????????????????????????????????????
? ????????????????????????????????? ?
? ? Child [Target][CurrentTarget] ? ?
? ????????????????????????????????? ?
? Parent Element ?
???????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
然后将此事件作为子元素作为Target传递给父元素的事件处理程序,将父元素作为CurrentTarget传递给父元素
???????????????????????????????????????
? ????????????????????????????????? ?
? ? Child [Target] ? ?
? ????????????????????????????????? ?
? Parent [CurrentTarget] ?
???????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
然后,事件以相同的方式连续传递给dom树中更高的元素,直到达到顶级元素或任何事件处理程序通过调用event.stopPropagation()取消此事件冒泡
那么当您创建将第三个参数useCapture传递为true的事件处理程序时会发生什么.
parentElement.addEventListener('click', myClickHandler, true);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,事件首先传递给父元素[ currentTarget:Parent ],然后传递给子元素[ currentTarget:Child ],但与往常一样,事件目标始终是子元素,因为这是触发事件的位置.
关于CurrentTarget 这个MDN WebDocs页面说,
当事件遍历DOM时,标识事件的当前目标.它总是引用事件处理程序附加到的元素,而不是event.target,它标识事件发生的元素.
没关系,我没有注意到事件中“ currentTarget ”元素的可用性,这正是我正在寻找的。
因此,不应使用“ event.target ”,而应使用“ event.currentTarget ”来获取触发事件的真实父元素。
这是一个有效的 JSFiddle:https ://jsfiddle.net/xs20xy27/
更新的JS:
function onDrag(ev){
var el = ev.srcElement;
console.log("Drag: " + ev.srcElement.outerHTML)
ev.dataTransfer.setData('text/html', ev.srcElement.outerHTML);
}
function onContainerOver(ev){
ev.preventDefault();
ev.dataTransfer.dropEffect = "move"
}
function onContainerDrop(ev){
ev.preventDefault();
console.log("Drop: " + ev.dataTransfer.getData("text/html"))
ev.currentTarget.innerHTML = ev.dataTransfer.getData("text/html");
}
document.getElementById('target').addEventListener('drop', onContainerDrop, true); // This should not bubble, but it does. Target is always the child first rather than the element where the event listener resides. Why???
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1478 次 |
| 最近记录: |