[英]Simulating drag and drop on a SortableJS sortable list using JavaScript
I'm attempting to simulate a drag and drop action on a sortable HTML list created using the Sortable library .我正在尝试在使用Sortable library创建的可排序 HTML 列表上模拟拖放操作。 It uses the native HTML5 API to implement draggable elements and sorting within a list.
它使用原生 HTML5 API 来实现可拖动元素和列表内的排序。
To simulate these drag events, I found and modified the following JavaScript code:为了模拟这些拖动事件,我找到并修改了以下 JavaScript 代码:
var triggerSortableDragAndDrop = function (selectorDrag, selectorDrop, callback) {
var DELAY_INTERVAL_MS = 10;
var MAX_TRIES = 2;
// fetch target elements
var elemDrag = document.querySelector(selectorDrag);
var elemDrop = document.querySelector(selectorDrop);
elemDrag.setAttribute('draggable',"true");
elemDrop.setAttribute('draggable',"true");
elemDrag.href="#";
var dragItems = document.querySelectorAll('[draggable=true]');
if (!elemDrag || !elemDrop) {
console.log("can't get elements");
return false;
}
var startingDropRect = elemDrop.getBoundingClientRect();
function rectsEqual(r1, r2) {
return r1.top === r2.top && r1.right === r2.right && r1.bottom === r2.bottom && r1.left === r2.left;
}
// function for triggering mouse events
function fireMouseEvent(type, elem) {
var evt = document.createEvent('MouseEvent');
evt.initMouseEvent(type, true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem);
elem.dispatchEvent(evt);
};
// trigger dragging process on top of drop target
// We sometimes need to do this multiple times due to the vagaries of
// how Sortable manages the list re-arrangement
var counter = 0;
function dragover() {
counter++;
console.log('DRAGOVER #' + counter);
var currentDropRect = elemDrop.getBoundingClientRect();
if (rectsEqual(startingDropRect, currentDropRect) && counter < MAX_TRIES) {
if (counter != 1) console.log("drop target rect hasn't changed, trying again");
// mouseover / mouseout etc events not necessary
// dragenter / dragleave events not necessary either
fireMouseEvent('dragover', elemDrop);
setTimeout(dragover, DELAY_INTERVAL_MS);
} else {
if (rectsEqual(startingDropRect, currentDropRect)) {
console.log("wasn't able to budge drop target after " + MAX_TRIES + " tries, aborting");
fireMouseEvent('drop', elemDrop);
if (callback) callback(false);
} else {
setTimeout(drop, DELAY_INTERVAL_MS);
}
}
}
function drop() {
console.log('DROP');
// release dragged element on top of drop target
fireMouseEvent('drop', elemDrop);
fireMouseEvent('mouseup', elemDrop); // not strictly necessary but I like the symmetry
if (callback) callback(true);
}
// start dragging process
console.log('DRAGSTART');
fireMouseEvent('mousedown', elemDrag);
console.log('mousedown triggered');
fireMouseEvent('dragstart', elemDrag);
console.log('dragstart triggered');
// after a delay, do the first dragover; this will run up to MAX_TRIES times
// (with a delay between each run) and finally run drop() with a delay:
setTimeout(dragover, DELAY_INTERVAL_MS);
return true;
};
And the markup of the section I'm trying to drag and drop with is as follows:我试图拖放的部分的标记如下:
When I tried to set breakpoints on the browser's drag event listeners, and execute the helper function in my browser console using:当我尝试在浏览器的拖动事件侦听器上设置断点,并使用以下命令在浏览器控制台中执行辅助函数时:
triggerSortableDragAndDrop('#bookmarkItems > li:nth-child(2)', '#bookmarkItems > li:nth-child(2)');
I noticed that the dragstart event was never captured, but the mousedown and dragover events were.我注意到 dragstart 事件从未被捕获,但 mousedown 和 dragover 事件被捕获。
How can I get the dragstart event fire to trigger its listener?如何触发 dragstart 事件以触发其侦听器? Because I think that is what's causing the drag and drop simulation to fail.
因为我认为这就是导致拖放模拟失败的原因。
I can see in your code the dragstart
event is created of type MouseEvent
while it is of type DragEvent
.我可以在您的代码中看到
dragstart
事件创建的类型为MouseEvent
而它的类型为DragEvent
。
var elem = document.getElementById("one"); var mousedown = document.createEvent('MouseEvent'); mousedown.initMouseEvent("mousedown", true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem); elem.dispatchEvent(mousedown); var dragstart = document.createEvent('DragEvent'); dragstart.initMouseEvent("dragstart", true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem); elem.dispatchEvent(dragstart);
<div id="one" draggable="true" onmousedown="console.log('mousedown')" ondragstart="console.log('dragstart')">drag me</div>
Creating the dragstart
as an event of the correct type, at least on Chrome and Edge, it works.将
dragstart
创建为正确类型的事件,至少在 Chrome 和 Edge 上,它是有效的。
Hope this helps.希望这可以帮助。
I used a more modern approach to trigger the dragstart
and mousedown
events (note that using event constructors is preferable over document.createEvent()
).我使用了一种更现代的方法来触发
dragstart
和mousedown
事件(请注意, 使用事件构造函数比document.createEvent()
更可取)。 Both events work as expected.这两个事件都按预期工作。 Some code to illustrate that below:
一些代码来说明如下:
let text = document.getElementById('image'); text.addEventListener('dragstart', () => { console.log('dragstart triggered') }); text.addEventListener('mousedown', () => { console.log('mousedown triggered') }); function btn_click() { const evt_1 = new MouseEvent('mousedown'); text.dispatchEvent(evt_1); const evt_2 = new DragEvent('dragstart'); text.dispatchEvent(evt_2); }
<p>Drag around the image to trigger the ondragstart and mousedown event.</p> <button onclick='btn_click()'>Programatically trigger the ondragstart and onmousedown events.</button> <br> <br> <img id='image' src='https://via.placeholder.com/150'>
However there is a big unknown in your code;但是,您的代码中有一个很大的未知数; How does the library you are using handle these events?
您使用的库如何处理这些事件? Does it even handle the
ondragstart
event?它甚至处理
ondragstart
事件吗? It may very well only use other events, thus you can't assume these events in your JS code.它很可能只使用其他事件,因此您不能在 JS 代码中假设这些事件。 The main issue is the coupling between your JS and that in the library.
主要问题是您的 JS 与库中的 JS 之间的耦合。
So there are 2 ways to go about this所以有两种方法可以解决这个问题
PS: If you are writing tests, you may decide not to test the library and trust it to behave as expected. PS:如果您正在编写测试,您可能决定不测试该库并相信它会按预期运行。 Maybe you can validate whether your implementation of the library is correct instead.
也许您可以验证您对库的实现是否正确。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.