当前位置: 首页 > 知识库问答 >
问题:

使用JavaScript在SortableJS可排序列表上模拟拖放

施子民
2023-03-14

我试图在使用可排序库创建的可排序HTML列表上模拟拖放操作。它使用本机HTML5API实现可拖动元素和列表中的排序。

为了模拟这些拖动事件,我找到并修改了以下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;
};

我尝试拖放的部分的标记如下:

当我尝试在浏览器的拖动事件侦听器上设置断点,并在浏览器控制台中使用以下命令执行helper函数时:

triggerSortableDragAndDrop('#bookmarkItems > li:nth-child(2)', '#bookmarkItems > li:nth-child(2)');

我注意到dragstart事件从未被捕获,但mousedown和dragover事件被捕获。

如何让dragstart事件触发其侦听器?因为我认为这就是导致拖放模拟失败的原因。

共有2个答案

甄正信
2023-03-14

我使用了一种更现代的方法来触发dragstartmousedown事件(注意,使用事件构造函数比使用document.createEvent()更可取)。这两项活动都按预期进行。下面是一些代码来说明这一点:

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'>
琴宾鸿
2023-03-14

我可以在您的代码中看到,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>
 类似资料:
  • 我正在尝试实现jQuery可排序和拖放上传的组合。基本布局是使用jQuery sortable对图像/对象进行排序的网格。通过拖动图像,我可以按照我想要的任何顺序重新排列图像。同时,我可以通过拖放包含网格的div上的任意位置,从文件系统上载新图像,并且图像在完成上载后显示在网格上的第一个位置。现在,我想让用户能够将文件拖到网格中的任何位置,然后将上载的图像显示在网格上的特定位置(同时相应地重新排列

  • 我试图将jQuery可拖动、可拖放和可排序相结合;然而,我一直有问题。有人能帮帮我吗? A、 B、C、D、E瓷砖可在上部可放下和可分拣之间移动 此外,我正试图在必要时在任何位置停用和重新激活所有这些。 这是我的,但它很有缺陷,也不漂亮: JS 超文本标记语言

  • 我正在尝试创建一个各种各样的仪表板,其中包含各种大小的小部件。我希望用户能够安排他们的小部件,以他们喜欢的。 我一直在尝试使用Portlet示例实现jQueryUI的可排序交互,但遇到了一些问题。 我可以在同一行中的列之间拖放/重新排列容器。 相关超文本标记语言: 相关CSS: 相关jQuery:

  • 问题内容: 我有一组三个列表项,它们希望在页面加载时从高到低自动显示。理想情况下使用jquery或javascript。 每个列表项都需要有自己的ID,因为它们每个都有各自的背景图像。数字必须是文本节点,以便用户可以编辑它们。 问题答案: 这可能是最快的方法,因为它不使用jQuery: 像下面这样调用函数: 您可以以相同的方式对其他列表进行排序,如果列表类在同一页面上还有其他元素,则应给您的ul一

  • 问题内容: 在AngularJS中的元素 上是否易于使用 ? 如果重新排序项目会很棒,那就是将自动传播的订单重新排列到源数组中。恐怕这两个系统会打架。有一个更好的方法吗? 问题答案: Angular UI具有可排序的指令,请单击此处进行演示 位于ui-sortable的代码,用法:

  • 我正在尝试实现一个类似问题的系统。这些问题应该根据数据属性“投票”重新排序。因此,每次从套接字接收到like事件时,都会调用sort函数。当一个问题第一次被喜欢时,所有的事情都很好,列表也被排序了。但它会停止排序。我已经检查了数据值。 下面是我的js功能: