Вы можете симулировать события мыши, используя интерфейс MouseEvent
, и перетаскивать события, используя интерфейс DragEvent
. Вы должны запустить правильную последовательность, используя EventTarget.dispatchEvent()
.
Я предполагаю, что вы объединяете "HTML Drag and Drop API" с "Мышью events " для создания поведения перетаскивания, поэтому я предоставлю один для имитации Drag & Drop и один для имитации Захват мыши и движение мыши .
Имитация Захват мыши и движение мыши
Пожалуйста, прочитайте встроенные комментарии
// 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);
Запустите фрагмент кода. Элемент квадратного 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>
Имитация Drag n Drop
Пожалуйста, прочитайте встроенные комментарии
// 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);
Запустите фрагмент кода и нажмите кнопку имитации, чтобы вызвать последовательность событий перетаскивания n:
// 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>