当鼠标已经在元素上并且已经移动时,如何启用可拖动?
How can I enable draggable when mouse is already down on element and already moved?
我编写了代码,允许在鼠标悬停在该元素上一段时间后拖动 HTML 元素。
问题是,当我使用本机 HTML 拖放时,我启用了 draggable
属性 当此超时已到(鼠标已按下)那个时间段内的元素),如果在超时之前鼠标已经被移动,HTML 将不会触发 dragstart
事件,甚至不会开始拖动元素。
下面有一个例子。
var t;
function startDelayedDrag() {
clearTimeout(t);
document.getElementById('dragtarget').draggable = false;
console.log('mousedown')
t = setTimeout(function() {
console.log('dragging enabled')
document.getElementById('dragtarget').draggable = true;
}, 1000);
}
.droptarget {
float: left;
width: 100px;
height: 35px;
margin: 15px;
padding: 10px;
border: 1px solid #aaaaaa;
user-select: none;
}
<div class="droptarget">
<p onmousedown="startDelayedDrag()" id="dragtarget">Drag me!</p>
</div>
<div class="droptarget"></div>
这个问题很棘手,可能与您的想法不同,但这里有一个解决问题的方法:
- 开始拖动事件
- 通过使用
setDragImage
设置图像来隐藏拖动对象
- 克隆拖动元素节点,隐藏克隆并将其添加到文档中(因为无法更改
setDragImage
设置的图像)
- 启动超时改变ghost元素的可见性
这还可以在很多方面进行改进,但我认为您可以了解它的工作原理。作为参考,请参阅以下代码段:
const [$drag] = document.getElementsByClassName('drag')
const [$pixel] = document.getElementsByClassName('pixel')
let $ghost = null
$drag.addEventListener("dragstart", e => {
// set the current draged element invisible
e.dataTransfer.setDragImage($pixel, 0, 0)
// create a ghost element
$ghost = $drag.cloneNode(true)
$ghost.style.position = "absolute"
$ghost.style.display = "none"
document.body.appendChild($ghost)
setTimeout(() => {
$ghost.style.display = 'block'
}, 1000)
})
$drag.addEventListener("drag", e => {
// keep the ghost position to follow the mouse while dragging
$ghost.style.left = `${e.clientX}px`
$ghost.style.top = `${e.clientY}px`
}, false);
$drag.addEventListener("dragend", e => {
// remove the ghost
if ($ghost.parentNode) $ghost.parentNode.removeChild($ghost)
}, false)
.content {
display: flex;
}
.box {
width: 100px;
height: 35px;
padding: 10px;
margin: 10px;
border: 1px solid #aaaaaa;
}
.drop {
user-select: none;
}
.drag {
text-align: center;
}
.pixel {
width: 1px;
height: 1px;
background-color: white;
}
<div class="content">
<div draggable="true" class="drag box">Drag</div>
<div class="drop box"></div>
<div class="pixel"></div>
</div>
我编写了代码,允许在鼠标悬停在该元素上一段时间后拖动 HTML 元素。
问题是,当我使用本机 HTML 拖放时,我启用了 draggable
属性 当此超时已到(鼠标已按下)那个时间段内的元素),如果在超时之前鼠标已经被移动,HTML 将不会触发 dragstart
事件,甚至不会开始拖动元素。
下面有一个例子。
var t;
function startDelayedDrag() {
clearTimeout(t);
document.getElementById('dragtarget').draggable = false;
console.log('mousedown')
t = setTimeout(function() {
console.log('dragging enabled')
document.getElementById('dragtarget').draggable = true;
}, 1000);
}
.droptarget {
float: left;
width: 100px;
height: 35px;
margin: 15px;
padding: 10px;
border: 1px solid #aaaaaa;
user-select: none;
}
<div class="droptarget">
<p onmousedown="startDelayedDrag()" id="dragtarget">Drag me!</p>
</div>
<div class="droptarget"></div>
这个问题很棘手,可能与您的想法不同,但这里有一个解决问题的方法:
- 开始拖动事件
- 通过使用
setDragImage
设置图像来隐藏拖动对象
- 克隆拖动元素节点,隐藏克隆并将其添加到文档中(因为无法更改
setDragImage
设置的图像) - 启动超时改变ghost元素的可见性
这还可以在很多方面进行改进,但我认为您可以了解它的工作原理。作为参考,请参阅以下代码段:
const [$drag] = document.getElementsByClassName('drag')
const [$pixel] = document.getElementsByClassName('pixel')
let $ghost = null
$drag.addEventListener("dragstart", e => {
// set the current draged element invisible
e.dataTransfer.setDragImage($pixel, 0, 0)
// create a ghost element
$ghost = $drag.cloneNode(true)
$ghost.style.position = "absolute"
$ghost.style.display = "none"
document.body.appendChild($ghost)
setTimeout(() => {
$ghost.style.display = 'block'
}, 1000)
})
$drag.addEventListener("drag", e => {
// keep the ghost position to follow the mouse while dragging
$ghost.style.left = `${e.clientX}px`
$ghost.style.top = `${e.clientY}px`
}, false);
$drag.addEventListener("dragend", e => {
// remove the ghost
if ($ghost.parentNode) $ghost.parentNode.removeChild($ghost)
}, false)
.content {
display: flex;
}
.box {
width: 100px;
height: 35px;
padding: 10px;
margin: 10px;
border: 1px solid #aaaaaa;
}
.drop {
user-select: none;
}
.drag {
text-align: center;
}
.pixel {
width: 1px;
height: 1px;
background-color: white;
}
<div class="content">
<div draggable="true" class="drag box">Drag</div>
<div class="drop box"></div>
<div class="pixel"></div>
</div>