Как поменять местами тексты (value) двух input при помощи drag and Drop на JavaScript или jQuery?

Рейтинг: 0Ответов: 1Опубликовано: 26.07.2023

Задача состоит в том, чтобы при переносе текста из одного инпута в другой их тексты поменялись местами. Количество инпутов будет генерироваться автоматически, поэтому поменять местами при помощи имен классов или id не представляется возможным. Подскажите, реализуемо ли это при помощи jQuery и, если нет, то как сделать подобное на JavaScript.

$( function() {
    $(".dragElement").draggable({
      axis: "y",
      containment: parent,
      cursor: "grabbing",
      opacity: 0.5,
      snap: true,
      snapTolerance: 100
    });
    $("#parent").sortable();
  } );
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>


<div id="parent" style="border:1px solid black">
  <div class="dragElement" style="border:1px solid black">
    <input value="Drag and drop 1">
  </div>
  <div class="dragElement" style="border:1px solid black">
   <input value="Drag and drop 2">
  </div>
  <div class="dragElement" style="border:1px solid black">
    <input value="Drag and drop 3">
  </div>
</div>

P.S. Если делать по события drag/drop dragstart/dragover, то я смогу узнать только текст инпута, из которого беру текст. Как тогда узнать текст инпута, в который я буду класть значение, чтобы просто поменять их местами?

Ответы

▲ 1Принят

Подскажите, реализуемо ли это при помощи jQuery

Возможно в другом ответе подскажут, я уже плоховато соображаю, ваш код так и не завёл без ошибок.

как сделать подобное на JavaScript

А вот на это отвечу.
Воспользуемся нативным drag and drop API в HTML5. Уже 23 год, вряд ли вам нужна реализация на HTML4, хотя если JQuery используете, всякое возможно.

document.addEventListener("DOMContentLoaded", function() {
  let draggedElement;

  document.addEventListener("dragstart", function(event) {
    draggedElement = event.target;
  });

  document.addEventListener("dragover", function(event) {
    event.preventDefault();
  });

  document.addEventListener("drop", function(event) {
    event.preventDefault();
    if (event.target.classList.contains("dragElement")) {
      const targetValue = event.target.querySelector("input").value;
      const draggedValue = draggedElement.querySelector("input").value;

      event.target.querySelector("input").value = draggedValue;
      draggedElement.querySelector("input").value = targetValue;
    }
  });
});
<div id="parent" style="border:1px solid black">
  <div class="dragElement" style="border:1px solid black" draggable="true">
    <input value="Drag and drop 1">
  </div>
  <div class="dragElement" style="border:1px solid black" draggable="true">
    <input value="Drag and drop 2">
  </div>
  <div class="dragElement" style="border:1px solid black" draggable="true">
    <input value="Drag and drop 3">
  </div>
</div>

Когда начинается перетаскивание, сохраняем элемент в переменную draggedElement. При событии drop, проверяем, является ли целевой элемент элементом с классом dragElement. Если это так, то меняем значения их инпутов местами.

Да, здесь пользуемся классом, но это ваше ограничение не совсем понимаю:

Количество инпутов будет генерироваться автоматически, поэтому поменять местами при помощи имен классов или id не представляется возможным.

Множьте сколько угодно, класс то у них одинаковый будет. И атрибут draggable необходимо добавить.


По комментариям. Вот пример на interact:

interact('.dragElement')
  .draggable({
    listeners: {
      start(event) {
        const target = event.target;
        const isDraggable = target.getAttribute('data-draggable') === 'true';
        if (!isDraggable) {
          event.preventDefault();
        }
      },
      move(event) {
        const target = event.target;
        if (!target.getAttribute('data-draggable') === 'true') {
          return;
        }
        const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
        const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

        target.style.transform = `translate(${x}px, ${y}px)`;

        target.setAttribute('data-x', x);
        target.setAttribute('data-y', y);
      },
      end(event) {
        const target = event.target;
        if (!target.getAttribute('data-draggable') === 'true') {
          return;
        }
        target.removeAttribute('data-x');
        target.removeAttribute('data-y');

        const targetValue = target.querySelector('input').value;
        const siblings = [...target.parentNode.children].filter(
          (el) => el !== target
        );
        const nearestElement = siblings.reduce((prev, curr) => {
          const prevRect = prev.getBoundingClientRect();
          const currRect = curr.getBoundingClientRect();
          return Math.abs(currRect.top - prevRect.top) <
            Math.abs(target.getBoundingClientRect().top - prevRect.top) ?
            curr :
            prev;
        });

        const draggedValue = nearestElement.querySelector('input').value;

        target.querySelector('input').value = draggedValue;
        nearestElement.querySelector('input').value = targetValue;

        target.style.transform = ''; // Reset transform after swapping
      },
    },
  });
<script src="https://cdn.jsdelivr.net/npm/interactjs@1.10.11/dist/interact.min.js"></script>

<div id="parent" style="border: 1px solid black">
  <div class="dragElement" style="border: 1px solid black">
    <input value="Drag and drop 1">
  </div>
  <div class="dragElement" style="border: 1px solid black">
    <input value="Drag and drop 2">
  </div>
  <div class="dragElement" style="border: 1px solid black">
    <input value="Drag and drop 3">
  </div>
</div>

Тут уже с Android работает. Немного кривовато, но всё же :)
Вопрос то не об этом был.