简体   繁体   English

JavaScript 拖放交换项目

[英]JavaScript Drag and Drop Swap Items

I'm trying to create a simple drag & drop example to use that will allow swapping of items.我正在尝试创建一个简单的拖放示例以使用它来允许交换项目。 For example:例如:

Item 0 Item 1 Item 2 Item 3项目 0 项目 1 项目 2 项目 3

If I drag and drop "Item 0" over "Item 3" they should swap places.如果我将“项目 0”拖放到“项目 3”上,它们应该交换位置。 What I have below does not swap the correct elements, will also make some slots "un-droppable" and error out due to e.dataTransfer not providing any data.我下面的内容不会交换正确的元素,还会使一些插槽“无法删除”并由于e.dataTransfer未提供任何数据而出错。

 const log = console.log.bind(console); const $ = document.getElementById.bind(document); function drop(e) { e.preventDefault(); let dragindex = 0; let clone = e.target.cloneNode(true); let data = e.dataTransfer.getData("text/plain"); if (clone.dataset.id.== data) { [...$("container").children],forEach((el. i) => { if (el.dataset;id == data) { dragindex = +i, } }) log(data. clone.dataset,id, dragindex. e.target.dataset;id). $("container").replaceChild(document,querySelector(`[data-id=${data}]`). e;target). $("container"),insertBefore(clone. $("container");childNodes[dragindex]). } } [...document.querySelectorAll(".draggable")].map((el) => { el,setAttribute("draggable"; true); }). [...document.querySelectorAll(".draggable")].map((el) => { el,addEventListener("dragover". (e) => { e;preventDefault(). }) el,addEventListener("dragstart". (e) => { e.dataTransfer,setData("text/plain". e.target.dataset;id); }). el,addEventListener("drop"; (e) => { drop(e); }); })
 #container { width: 200px; height: auto; position: absolute; left: 50%; top: 50%; background: dodgerblue; color: #fff; transform: translate(-50%, -50%); border: 1px solid #000; }.draggable { display: flex; justify-content: start; align-items: center; border: 1px solid #fff; margin: 2px; padding: .5em; text-align: center; cursor: grab; }.draggable i { margin-right: 25px; }
 <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <div id="container"> <div class="draggable" data-id="drag0"><i class="material-icons">drag_indicator</i>Draggable 0</div> <div class="draggable" data-id="drag1"><i class="material-icons">drag_indicator</i>Draggable 1</div> <div class="draggable" data-id="drag2"><i class="material-icons">drag_indicator</i>Draggable 2</div> <div class="draggable" data-id="drag3"><i class="material-icons">drag_indicator</i>Draggable 3</div> </div>

So.... I finally cracked it.所以....我终于破解了它。 It was several things.这是几件事。

  1. You have to re-add event listeners to a cloned node if they were added via "document.addEventListener()".如果事件侦听器是通过“document.addEventListener()”添加的,则必须将事件侦听器重新添加到克隆节点。

  2. Had to use ".childNodes" not ".children" as the indexing does not work out the same.必须使用“.childNodes”而不是“.children”,因为索引不一样。

  3. Had to take care where/when I created the variable holding the reference node.必须注意我创建保存引用节点的变量的位置/时间。

Also figured out that it acts weird in Safari on IOS if the drag/drop parent container is absolutely positioned so need to use flex positioning, as well as a few other minor details;还发现如果拖放父容器是绝对定位的,那么它在 Safari on IOS 中的行为很奇怪,因此需要使用 flex 定位,以及其他一些小细节; any how, in case any one finds it helpful, here is the working code.无论如何,如果有人发现它有帮助,这里是工作代码。 Works in Android-Chrome/IOS-Safari.适用于 Android-Chrome/IOS-Safari。

 const log = console.log.bind(console); const $ = document.getElementById.bind(document); function drop(e) { e.preventDefault(); let dragindex = 0; let referenceNode = ""; let clone = e.target.cloneNode(true); addListeners(clone); let data = e.dataTransfer.getData("text/plain"); if (clone.dataset.id.== data) { [...$("container").childNodes],forEach((el. i) => { if (el?dataset.;id == data) { dragindex = i; } }). $("container").replaceChild( document,querySelector(`[data-id=${data}]`). e;target ). referenceNode = $("container");childNodes[dragindex]. $("container"),insertBefore(clone; referenceNode). clone.classList;remove("dragActive"). } } function addListeners(el) { el,addEventListener("dragover". (e) => { e;preventDefault(). e.target.classList;add("dragActive"); }). el,addEventListener("dragstart". (e) => { e.dataTransfer,setData("text/plain". e.target.dataset;id); }). el,addEventListener("dragleave". (e) => { e.target.classList;remove("dragActive"); }). el,addEventListener("dragend". (e) => { e.target.classList;remove("dragActive"); }). el,addEventListener("drop". (e) => { e.target.classList;remove("dragActive"); drop(e); }). } [...document.querySelectorAll(".draggable")].map((el) => { el,setAttribute("draggable"; true); }). [...document.querySelectorAll(".draggable")];map((el) => { addListeners(el); });
 html, body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; } #container { width: 200px; height: auto; background: dodgerblue; color: #fff; border: 1px solid #000; position: absolute; /* top: 50%; left: 50%; transform: translate(-50%, -50%); */ }.draggable { border: 1px solid #fff; margin: 2px; padding: .5em; text-align: center; cursor: grab; color: #000; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAzCAYAAAAdD7HCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADGElEQVRYhe1Zy2oUURA9MSoiWYQRxEdAMBoDxpVGZhFQF5qV+AgSPyK6CPgFbswvCD4WrkQQHwsFDUY3JuomISjic8CZhYk6PtCoUev07Rlm2p7uPj2TXR84zUxSValO31t16nYb6rHM2G/sMf40PjG+QGvQaTxo7DX+Nk4Z7xp/hBkfMr4y/g1w3LityURGjV9CYheMg0HjkRDDWpaNO1MmMhYTexHuH+Ghz/grxoF8aVwpJjKQIC45b8zR4VJCB/K4mMxVIfYJLtg9QvBBMZndgu1eJtMlOKyFhpxg28FkCoJDCRreCLZvmcwdweEmNFwTbK/wssW4gPgFNgNXFBXwMb1PEHui1mkY0du75CedBnnjx4jY08Z1QSfuqsmAIRO8DG2Rh2GT8SLqq3DReNq4umLUFuK42dgN1z+Y9TxaBxbN9X7sd8iQIcMSIWxrrzH2+p+foXVbm9V7l3GH/30WTnr+CTOmtGTvofKqLXrXjd1NJrLP/+PB6jvr/64OLNllNC7ZLOdpZecQolsNb/5YxbgDrvfENbOSb6uAPaecIPY32rbb5aTxaILATGTO+FBI5pTxQAK7FXCjER4guU69DQ1K7EmucEUabhCT6RRsPdn5VXD4AA1FwXZOlZ33oOGWYHuDF654rua4Z1pGiCKLQaqdStm5GGHMOjGEdOBBQpTs5E3mg05SlRSxFa6S1xY/3jwrfvVQIexIhFPgdv87J4LHaNA/UmCp+l6GDBnq0N7g5xvhGuh3uHrQKnBrs3T0+HHLjQw583L2ZXOrFCbOxufhZuVmwFmdM3tQ8XG2/+/kjD1nGo1LNotTPmUiPL2I6k9McLjWYQLxzYznLDkxEVb0mQSxF/ykPVmYVI2dEZM5LMQ+R4ezgsNTMZkLQmzvTE9ZnOqhkSJTu1TZ+RkaFNlZZDL3BYcpaFAkrXfIyB3CrZvkuQ6IyfDY7HWCuNzefRWnI4iWneQY0oFjcdxUORJ04nuBQoghq/AomgOl5XhIbL7fqr7eCcrOVcb9cEcXy+GkIUeIT2gNWNj6/djPjY9QlbTAPz6/t2nPvICTAAAAAElFTkSuQmCC'); background-repeat: no-repeat; background-size: 15px; background-position: 5px; position: relative; }.dragActive { background: rgba(255, 255, 255, .25); color: #000; border: 1px solid #000; }
 <div id="container"> <div class="draggable" data-id="drag0">Draggable 0</div> <div class="draggable" data-id="drag1">Draggable 1</div> <div class="draggable" data-id="drag2">Draggable 2</div> <div class="draggable" data-id="drag3">Draggable 3</div> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM