如何在拖放中停止 dragend 的默认行为?
Posted
技术标签:
【中文标题】如何在拖放中停止 dragend 的默认行为?【英文标题】:How to stop dragend's default behavior in drag and drop? 【发布时间】:2017-10-02 11:33:14 【问题描述】:我很难用语言来概括这个错误。所以我为这个错误创建了video。 基本上,当 dragEnd 被调用时,元素的动画就像去原来的地方一样。如何停止默认行为?我也为此制作了fiddle 和codepen。
我的示例有两个列表,在释放鼠标按钮后调用 dragEnd 时。一个列表中的元素将动画显示到其原始位置的列表,而不是它将要到达的位置。
JS代码:
'use strict';
var source = null; var heightWidth = null; var lastDragOverElementId = null; var dragImageSource = null;
function listItemDragStartHandler(event)
source = event.currentTarget;
heightWidth = [];
heightWidth.push(source.offsetHeight);
heightWidth.push(source.offsetWidth);
event.dataTransfer.setData('text/html', event.currentTarget.innerHTML);
event.dataTransfer.effectAllowed = 'move';
// Drag image logic
dragImageSource = source.cloneNode(true);
dragImageSource.style.position = 'absolute';
// Don't show the element
dragImageSource.style.top = '0px';
dragImageSource.style.left = '-' + String(window.innerWidth) + 'px';
// dragImageSource.style.left = '-100px';
var toTiltElement = dragImageSource.getElementsByClassName('item-list-element')[0];
toTiltElement.style.transform = 'rotate(5deg)';
document.body.append(dragImageSource);
event.dataTransfer.setDragImage(dragImageSource, heightWidth[1]/2, heightWidth[0]/2);
function dragoverHandler(event)
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
source.style.display = 'none';
var currentElement = event.currentTarget;
var listContainer = currentElement.parentNode;
if (lastDragOverElementId != currentElement.getAttribute('id'))
lastDragOverElementId = currentElement.getAttribute('id');
if(document.getElementById('grayed-empty-node') !== null)
if(currentElement.getAttribute('id') !== 'grayed-empty-node')
document.getElementById('grayed-empty-node').remove();
var isGrayEmptyNodeThere = document.getElementById('grayed-empty-node'); //
if(isGrayEmptyNodeThere === null)
var emptyNode = document.getElementById('empty-node').cloneNode(true);
emptyNode.removeAttribute('id');
emptyNode.setAttribute('id', 'grayed-empty-node');
emptyNode.setAttribute('class', 'fade-in');
emptyNode.style.height = String(heightWidth[0]) + 'px';
emptyNode.style.width = String(heightWidth[1]) + 'px';
listContainer.insertBefore(emptyNode, currentElement);
function dragLeaveHandler(event)
event.preventDefault();
var currentElement = event.currentTarget;
var listContainer = currentElement.parentNode;
var elementList = listContainer.getElementsByClassName('item-template-container');
var visibleElementList = [];
var i = 0;
for (i=0; i<elementList.length; i++)
if (elementList[i].style.display !== 'none')
visibleElementList.push(elementList[i]);
// Last element ondragleave handler should be delayed, otherwise it
// would spin off chain reaction.
var lastVisibleElement = visibleElementList[visibleElementList.length - 1];
// Basically last element
if (currentElement.id === lastVisibleElement.getAttribute('id'))
lastVisibleElement.removeAttribute('ondragleave');
if(document.getElementById('grayed-empty-node') !== null)
document.getElementById('grayed-empty-node').remove();
var isGrayEmptyNodeThere = document.getElementById('grayed-empty-node');
if(isGrayEmptyNodeThere === null)
var listContainer = currentElement.parentNode;
var emptyNode = document.getElementById('empty-node').cloneNode(true);
emptyNode.removeAttribute('id');
emptyNode.setAttribute('id', 'grayed-empty-node');
emptyNode.setAttribute('class', 'fade-in');
emptyNode.style.height = String(heightWidth[0]) + 'px';
emptyNode.style.width = String(heightWidth[1]) + 'px';
listContainer.insertBefore(emptyNode, null);
// This delayed the chain reaction
setTimeout(function()
visibleElementList[visibleElementList.length - 1].setAttribute('ondragleave', 'dragLeaveHandler(event);');
, 500);
// When event is on last element set the lastDragOverElementId to null
// then dragover to lastVisibleElement(second last element) can be handled
// otherwise dragover to second last element won't show placeholder.
lastDragOverElementId = null;
function dragEndHandler(event)
event.preventDefault();
// Check the dropEffect
dragImageSource.remove();
var listElement = document.getElementById('grayed-empty-node')
var listContainer = listElement.parentNode;
if (event.dataTransfer.dropEffect === 'none')
var grayEmptyNode = document.getElementById('grayed-empty-node');
// When grayEmptyNode is null, that will append at the end.
listContainer.insertBefore(source, grayEmptyNode);
source.style.display = '';
if(document.getElementById('grayed-empty-node') !== null)
document.getElementById('grayed-empty-node').remove();
else if (event.dataTransfer.dropEffect === 'move')
var grayEmptyNode = document.getElementById('grayed-empty-node');
// When grayEmptyNode is null, that will append at the end.
listContainer.insertBefore(source, grayEmptyNode);
source.style.display = '';
if(document.getElementById('grayed-empty-node') !== null)
document.getElementById('grayed-empty-node').remove();
function delete_item(event)
var currentElement = event.currentTarget;
var grandParentOfDelete = currentElement.parentNode.parentNode;
grandParentOfDelete.remove();
function add_item()
var item_text_node = document.getElementsByName('add-item-text')[0]
var item_text = item_text_node.value;
if (item_text.length > 0)
var item_template = document.getElementById('item-template-container');
var item_clone = item_template.cloneNode(true);
item_clone.removeAttribute('id');
var random_id = (new Date().getTime() +
parseInt(Math.random(0, 1000) * 1000))
item_clone.setAttribute('id', random_id);
var clone_text = item_clone.getElementsByClassName('item-text')[0];
clone_text.textContent = item_text;
// reset the value
item_text_node.value = '';
var item_list = document.getElementById('item-list');
item_list.appendChild(item_clone);
else
alert('No text?? Add some text!');
function add_item_2()
var item_text_node = document.getElementsByName('add-item-text-2')[0]
var item_text = item_text_node.value;
if (item_text.length > 0)
var item_template = document.getElementById('item-template-container');
var item_clone = item_template.cloneNode(true);
item_clone.removeAttribute('id');
var random_id = (new Date().getTime() +
parseInt(Math.random(0, 1000) * 1000))
item_clone.setAttribute('id', random_id);
var clone_text = item_clone.getElementsByClassName('item-text')[0];
clone_text.textContent = item_text;
// reset the value
item_text_node.value = '';
var item_list = document.getElementById('item-list-2');
item_list.appendChild(item_clone);
else
alert('No text?? Add some text!');
function onEnterInInput()
var e = e || window.event;
if (e.keyCode == 13)
add_item()
function sample_data()
for(var i=0;i<10;i++)
var item_text_node = document.getElementsByName('add-item-text')[0]
item_text_node.value = i;
var item_text_node_2 = document.getElementsByName('add-item-text-2')[0]
item_text_node_2.value = i;
add_item();
add_item_2();
window.onload = function ()
sample_data();
HTML 代码:
<!DOCTYPE html>
<html>
<head>
<title>List task</title>
<script type="text/javascript" src="list-task.js"></script>
<link rel="stylesheet" type="text/css" href="list-task.css">
<script>
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>')
</script>
</head>
<body>
<div id="container">
<div id="list-1">
<div id="add-item-div">
<input type="text" name="add-item-text" onkeypress="onEnterInInput(event);">
<button id="add-item" onclick="add_item(event)">Add Item</button>
</div>
<div id="item-list">
</div>
</div>
<div id="list-2">
<div id="add-item-div-2">
<input type="text" name="add-item-text-2" onkeypress="onEnterInInput(event);">
<button id="add-item-2" onclick="add_item_2(event)">Add Item</button>
</div>
<div id="item-list-2">
</div>
</div>
<div id="item-template-container" class="item-template-container" draggable="true" ondragstart="listItemDragStartHandler(event);" ondragover="dragoverHandler(event);" ondragend="dragEndHandler(event);" ondragleave="dragLeaveHandler(event);" ondrop="onDropHandler(event);">
<div class="item-list-element">
<div class="item-text"></div>
<div class="delete-item-div">
<button class="delete-item" onclick="delete_item(event);">Delete</button>
</div>
</div>
</div>
<div id="empty-node"> </div>
</div>
</body>
</html>
描述错误的视频:https://www.youtube.com/watch?v=Uz_ukKdg1O0&feature=youtu.be
注意:我观察了 Mac 上的行为,不确定 Linux 和 Windows。
【问题讨论】:
动画在 jsfiddle 中不起作用。 它可以在带有 chrome 的 pc 中正常工作。 好的,但是你可以在视频中看到它发生在 Mac 的所有浏览器上。我应该制作另一个视频吗? 这很奇怪。我不知道。 嗨,我在我的 Mac 上的 Chrome 上看到了这个问题,但在 Safari 上根本没有拖动图像,因为你使用document.body.append()
,你应该改用document.body.appendChild()
,它会工作更多浏览器。我知道它不能解决你的问题,但如果你想对 Mac 用户友好,你可以尝试支持 Safari ;)
【参考方案1】:
在您的 dragend 事件处理程序中,您需要检测鼠标是否位于要放入的列表中的灰色框上。请注意,您需要编写查询元素 grayBoxInOtherList
的逻辑,但这就是您想要的需要做的:
if ($(grayBoxInOtherList).parent().find(":hover"))
listContainer.insertBefore(source, grayEmptyNode);
仅当您将鼠标悬停在 grayBoxInOtherList 上时才执行此操作:listContainer.insertBefore(source, grayEmptyNode);
【讨论】:
用户体验不需要用户将鼠标悬停在灰色框上,用户可以选择从浏览器的任何位置离开。所以这个解决方案不是我需要的。 从您的视频中,如果您在拖动时当前没有将鼠标悬停在新列表上的灰色框上,我认为您想返回原始位置。你能澄清一下期望的行为吗?以上是关于如何在拖放中停止 dragend 的默认行为?的主要内容,如果未能解决你的问题,请参考以下文章