在可拖动元素上模拟 3 像素拖动
Posted
技术标签:
【中文标题】在可拖动元素上模拟 3 像素拖动【英文标题】:simulate a 3 pixel drag on draggable elem 【发布时间】:2020-08-06 03:10:26 【问题描述】:我只是想模拟一个小的点击并拖动一个可拖动的 div 元素——我在这里找到了几个类似的问题,但都涉及使用额外的插件......
是否有纯 javascript 或 jQuery 功能来专门处理拖动?据我所知.click();
或鼠标按下可以被调用来启动。
我并不是要创建拖放功能,我已经拥有了。我正在尝试创建一个自动模拟此事件的小函数。 单击 > 按住 > 向上拖动 3 个像素
更新:在不使用第三方库的情况下,在 SO 或其他地方找不到任何关于此的内容,因此创建了 500 赏金。当然有可能。
【问题讨论】:
我对此一无所知。您必须为该自定义“模拟”创建动画。由于您的问题中没有代码,因此我将投票结束,因为需要更多关注...旧术语太宽泛会很准确。 @LouysPatriceBessette 不错,不错 您是否尝试过触发按键和鼠标移动事件? 如果您想自动激活现有的拖放行为,您应该向我们展示您是如何实现该功能的。 【参考方案1】:您可以使用MouseEvent
接口模拟鼠标事件和使用DragEvent
接口拖动事件。您必须使用EventTarget.dispatchEvent()
触发正确的序列。
我猜你将"html Drag and Drop API" 与"Mouse events" 结合起来创建拖放行为,所以我将提供一个模拟拖放和一个模拟鼠标捕获和鼠标移动。
模拟鼠标捕获和鼠标移动
请阅读内联 cmets
// We create 3 mouse events using MouseEvent interface,
// one for mousedown to initiate the process,
// one for mousemove to handle to movement
// and one for mouseup to terminate the process
const mouseDownEvent = new MouseEvent('mousedown',
clientX: element.getBoundingClientRect().left,
clientY: element.getBoundingClientRect().top,
bubbles: true,
cancelable: true
);
const mouseMoveEvent = new MouseEvent('mousemove',
clientX: element.getBoundingClientRect().left + 3,
clientY: element.getBoundingClientRect().top,
bubbles: true,
cancelable: true
);
const mouseUpEvent = new MouseEvent('mouseup',
bubbles: true,
cancelable: true
);
// Dispatch the mousedown event to the element that has the listener
element.dispatchEvent(mouseDownEvent);
// For mousemove, the listener may be the parent or even the document
<element|document>.dispatchEvent(mouseMoveEvent);
// Dispatch mouseup to terminate the process
element.dispatchEvent(mouseUpEvent);
运行代码sn-p。方形 div 元素是可拖动的,您可以在模拟计时器未运行时单击并拖动它。单击模拟按钮以查看实际的模拟:
// Timer ID holder
let linearSimulationTimer;
// Simulation X/Y calculation
let calcX = 0, calcY = 0;
// Simulation X/Y axis orientation to handle parent collisions
let xAxisOrientation = 1, yAxisOrientation = 1;
// How many pixels to move the element for X/Y axis
const pixelsShift = 3;
// Elements
const simulateButton = document.getElementById('simulate-dnm');
const movable = document.getElementById('movable');
const movableContainer = movable.parentNode;
simulateButton.addEventListener('click', function()
// If there is a timer running
if (linearSimulationTimer)
// Stop and clear the timer
clearInterval(linearSimulationTimer);
linearSimulationTimer = null;
// Create a simple mouseup event with no custom properties
const mouseUpEvent = new MouseEvent('mouseup',
bubbles: true,
cancelable: true,
);
// Dispatch it to the movable element
movable.dispatchEvent(mouseUpEvent);
// Handle button label text (start/stop)
simulateButton.classList.remove('running');
// Else if there is no timer running
else
// Create the mousedown event using movable element client left/top for event clientX.clientY
const mouseDownEvent = new MouseEvent('mousedown',
clientX: movable.getBoundingClientRect().left,
clientY: movable.getBoundingClientRect().top,
pageX: 0,
pageY: 0,
bubbles: true,
cancelable: true,
view: window
);
// Dispatch the mousedown event to the movable element
movable.dispatchEvent(mouseDownEvent);
// Get movable parent client rect
const parentRect = movable.parentNode.getBoundingClientRect();
// Start the simulation timer
linearSimulationTimer = setInterval(() =>
// Get movable element size
const width, height = movable.getBoundingClientRect();
// Calculate new X/Y position and orientation
calcX += pixelsShift * xAxisOrientation;
calcY += pixelsShift * yAxisOrientation;
// If we hit movable parent X axis bounds, reverse X axis
if (calcX + width > parentRect.width)
calcX = parentRect.width - width;
xAxisOrientation = -xAxisOrientation;
else if (calcX < 0)
calcX = 0;
xAxisOrientation = -xAxisOrientation;
// If we hit movable parent Y axis bounds, reverse Y axis
if (calcY + height > parentRect.height)
calcY = parentRect.height - height;
yAxisOrientation = -yAxisOrientation;
else if (calcY < 0)
calcY = 0;
yAxisOrientation = -yAxisOrientation;
// Create mousemove event using calcX/calcY and the parent client position
const mouseMoveEvent = new MouseEvent('mousemove',
clientX: parentRect.left + calcX,
clientY: parentRect.top + calcY,
pageX: 0,
pageY: 0,
bubbles: true,
cancelable: true,
view: window
);
// Dispatch the mousemove event to the parent which it has the listener
movableContainer.dispatchEvent(mouseMoveEvent);
, 50);
// Handle button label text (start/stop)
simulateButton.classList.add('running');
);
// Mouse capture and drag handler (https://javascript.info/mouse-drag-and-drop)
movable.onmousedown = function(event)
let shiftX = event.clientX - movable.getBoundingClientRect().left;
let shiftY = event.clientY - movable.getBoundingClientRect().top;
moveAt(event.pageX, event.pageY);
function moveAt(pageX, pageY)
movable.style.left = pageX - shiftX - movableContainer.offsetLeft + 'px';
movable.style.top = pageY - shiftY - movableContainer.offsetTop + 'px';
function onMouseMove(event)
moveAt(event.pageX, event.pageY);
movableContainer.addEventListener('mousemove', onMouseMove);
movable.onmouseup = function()
movableContainer.removeEventListener('mousemove', onMouseMove);
movable.onmouseup = null;
movable.ondragstart = function()
return false;
#movable-container
position: relative;
height: 80px;
width: 200px;
margin: auto;
margin-bottom: 20px;
border: 1px dotted silver;
#movable
position: relative;
left: 0;
width: 30px;
height: 30px;
background-color: cornflowerblue;
border-radius: 5px;
border: 1px solid grey;
#simulate-dnm > span:before
content: 'Start ';
#simulate-dnm.running > span:before
content: 'Stop ';
<div id="movable-container">
<div id="movable"></div>
</div>
<div>
<button id="simulate-dnm"><span>Mouse capture & move simulation</span></button>
</div>
模拟拖放
请阅读内联 cmets
// We create 3 drag events using DragEvent interface,
// one for dragstart to initiate the process,
// one for drop to handle the drag element drop inside the drop container
// and one for dragend to terminate the process
const dragStartEvent = new DragEvent('dragstart',
bubbles: true,
cancelable: true
);
const dragEndEvent = new DragEvent('dragend',
bubbles: true,
cancelable: true
);
const dropEvent = new DragEvent('drop',
bubbles: true,
cancelable: true
);
// Dispatch the dragstart event to the source element to initiate
sourceNode.dispatchEvent(dragStartEvent);
// Dispatch the drop event to the destination element to get the drag
destinationNode.dispatchEvent(dropEvent);
// Dispatch the dragend event to the source element to finish
sourceNode.dispatchEvent(dragEndEvent);
运行代码 sn-p 并点击模拟按钮以触发拖放事件序列:
// The current parent index that the drag element is inside
let currentParentIndex = 0;
// Elements
const simulateButton = document.getElementById('simulate-dnd');
const sourceNode = document.getElementById('drag');
function simulateDragDrop(sourceNode, destinationNode)
// Create dragstart event
const dragStartEvent = new DragEvent('dragstart',
bubbles: true,
cancelable: true
);
// Create dragend event
const dragEndEvent = new DragEvent('dragend',
bubbles: true,
cancelable: true
);
// Create drop event
const dropEvent = new DragEvent('drop',
bubbles: true,
cancelable: true
);
// Dispatch dragstart event to the draggable element
sourceNode.dispatchEvent(dragStartEvent);
// Dispatch drop event to container element we want to drop the draggable
destinationNode.dispatchEvent(dropEvent);
// Dispatch dragend event to the draggable element
sourceNode.dispatchEvent(dragEndEvent);
simulateButton.addEventListener('click', function()
// Change drop container index to other container than the current
const newParentIndex = currentParentIndex === 0 ? 1 : 0;
// Get the drop container element
const destinationNode = document.getElementsByClassName('dropzone')[newParentIndex];
// Initiate simulation sequence
simulateDragDrop(sourceNode, destinationNode);
// Save the new container index
currentParentIndex = newParentIndex;
);
// Drag n Drop handling
let dragged;
document.addEventListener("dragstart", function(event)
// store a ref. on the dragged elem
dragged = event.target;
// make it half transparent
event.target.style.opacity = .5;
, false);
document.addEventListener("dragend", function(event)
// reset the transparency
event.target.style.opacity = "";
, false);
/* events fired on the drop targets */
document.addEventListener("dragover", function(event)
// prevent default to allow drop
event.preventDefault();
, false);
document.addEventListener("dragenter", function(event)
// highlight potential drop target when the draggable element enters it
if (event.target.className == "dropzone")
event.target.style.background = "yellow";
, false);
document.addEventListener("dragleave", function(event)
// reset background of potential drop target when the draggable element leaves it
if (event.target.className == "dropzone")
event.target.style.background = "";
, false);
document.addEventListener("drop", function(event)
// prevent default action (open as link for some elements)
event.preventDefault();
// move dragged elem to the selected drop target
if (event.target.className == "dropzone")
event.target.style.background = "";
dragged.parentNode.removeChild(dragged);
event.target.appendChild(dragged);
currentParentIndex = Array.prototype.indexOf.call(event.target.parentNode.children, event.target);
, false);
.dropzones
display: flex;
justify-content: space-evenly;
.dropzone
width: 100px;
height: 100px;
background-color: mintcream;
border-radius: 5px;
border: 2px dashed darkgrey;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 10px;
#drag
margin: unset;
width: 40px;
height: 40px;
background-color: coral;
border-radius: 4px;
border: 1px solid grey;
<div class="dropzones">
<div class="dropzone">
<div id="drag" draggable="true"></div>
</div>
<div class="dropzone"></div>
</div>
<div>
<button id="simulate-dnd">Simulate Drag & Drop</button>
</div>
【讨论】:
【参考方案2】:如果您的意思是“模拟拖动”,则触发 mousedown 事件,然后更新元素的位置,您应该能够执行以下操作:
let element = document.getElementById('draggable-div');
element.dispatchEvent(new Event('mousedown'));
element.style.top += 3
style.top
更改可能会也可能不会移动元素,具体取决于元素的定位方式(绝对、相对、粘性)。
如果您有尝试触发的拖放库。然后,您甚至可以通过简单地将元素移动到放置区域(向上 3 个像素)然后触发 mouseup 来模拟拖动:
let element = document.getElementById('draggable-div');
element.style.top += 3
element.dispatchEvent(new Event('mouseup'));
这个列表还在继续,因为现在还有拖动事件(尽管它们还没有被所有浏览器完全支持:https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API)。
但你的问题并不清楚你要进行什么样的模拟。
【讨论】:
这很奇怪,我看到 DOM 元素上对dispatchEvent
的支持可以追溯到很久以前。我们不是在拖动 DOM 元素吗? developer.mozilla.org/en-US/docs/Web/API/EventTarget/…
@docholiday 你能告诉我们你在哪里试过dispatchEvent
的代码吗?
还想补充一下有拖动事件以上是关于在可拖动元素上模拟 3 像素拖动的主要内容,如果未能解决你的问题,请参考以下文章