jQuery Draggable — создайте перетаскиваемый элемент и начните перетаскивать его в собственном событии API Drag And Drop в html5.

Хорошо, в основном то, чего я хочу попытаться достичь, это когда событие dragover срабатывает из HTML5 Drag And Drop API, я хочу создать объект jQuery draggable и начать следовать за мышью, в то время как событие dragend срабатывает из HTML5 Drag And Drop API.

Причина, по которой я хочу это сделать, заключается в следующем:

  • У меня есть приложение, которое использует плагин, функциональность которого зависит от функции jQuery.ui draggable (это плагин FullCalendar Scheduler, версия 3)
  • Я хочу добиться новой функциональности в приложении, с помощью которой клиент может перетаскивать что-то из окна браузера А и перетаскивать это в вышеупомянутый плагин в окно браузера Б.
  • Поскольку вышеупомянутый плагин не работает с родным HTML5 Drag and Drop API, а jQuery.ui draggable не умеет перетаскивать элементы из одного окна браузера в другое, я думаю, что мой единственный вариант - смешать эти два плагина.

Мое предложенное решение этой проблемы состояло в том, чтобы использовать собственный HTML5 Drag and Drop API и, когда перетаскиваемый элемент достигает dropzone, создавать новый перетаскиваемый элемент в окне браузера B и имитировать на нем событие mousedown, чтобы он начинает следовать за курсором. Когда сработает событие dragend, я планировал просто и просто сгенерировать событие mouseup для элемента draggable, и с этого момента плагин планировщика может творить чудеса.

Чтобы проверить это, сначала с одним окном браузера я попытался выполнить первую часть моего вышеуказанного решения, то есть: когда dragover срабатывает, создайте jQuery.ui draggable и смоделируйте на нем mousedown, тогда он должен запуститься вслед за мышью. Я не могу добиться такого поведения.

Я сделал скрипт, где вы можете увидеть, что я пробовал до сих пор (я не публикую здесь весь код, так как он довольно длинный): JSFiddle

По сути, ошибка, которую я получаю в Fiddle, с обоими вариантами, которые я пробовал, является ошибкой type.indexOf is not a function.

Я также спросил и получил некоторую помощь по следующим вопросам: без удержания-the/56590231?noredirect=1#comment99978220_56590231" rel="nofollow noreferrer">вопрос, откуда предлагаемое решение отлично работает при запуске операции перетаскивания с событием click, но оно не работает с любым другим типом события. Я полагаю, что могу имитировать событие mousedown.draggable только из MouseEvent, а событие dragend не является MouseEvent.

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


person Adam Baranyai    schedule 22.06.2019    source источник
comment
Я вижу одну проблему: когда вы пытаетесь обновить ev в dragover_handler, вы обновляете ev.type, но не ev.target. Затем событие привязывается не к вновь созданному элементу, а к исходному ev.target.   -  person Twisty    schedule 23.06.2019


Ответы (1)


Кажется, на это нет хорошего ответа. Во-первых, не все браузеры поддерживают одинаковую терминологию или функциональность DnD. Например, FireFox запускает событие dragenter при удалении, а Chrome, похоже, не обнаруживает событие drop, когда объект находится в другом окне.

Вот мое тестирование до сих пор. Для использования скопируйте содержимое в текстовый файл и сохраните его как HTM или HTML. Затем откройте файл локально в браузере. Откройте другое окно и откройте второй HTM. Теперь у вас есть два окна, которые вы можете перетаскивать.

wina-1.htm

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Window A</title>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <style>
  .items {
    position: relative;
  }
  .items > div {
    margin-right: 5px;
    width: 150px;
    height: 150px;
    padding: 0.5em;
    border-radius: 6px;
    display: inline-block;
  }
  #log {
    width: 100%;
    height: 5em;
    overflow-y: auto;
  }
  [draggable].idle {
    background-color: rgba(255,0,0,0.75); 
  }
  [draggable].selected {
    background-color: rgba(255,0,0,0.95);
  }
  </style>
</head>
<body>
<pre id="log"></pre>
<div class="items ui-widget">
  <div id="draggable" class="ui-widget-content idle" draggable="true">
    <p>Drag me around</p>
  </div>
  <div id="static" class="ui-widget-content">
    <p>I can't be moved</p>
  </div>
</div>
<script>

var srcEl;

function log(s){
  var now = new Date();
  var t = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() 

+ "." + now.getMilliseconds();
  var l = document.getElementById("log");
  l.append(t + ": " + s + "\r\n");
  l.scrollTop = l.scrollHeight;
}

function dragStart(e){
  log("Drag Start: " + e.target.nodeName + "#" + e.target.id);
  srcEl = e.target;
  if(e.dataTransfer == undefined){} else {
    e.dataTransfer.effectAllowed = "copyMove";
    log("Event dataTransfer.effectAllowed: " + 

e.dataTransfer.effectAllowed);
    log("Source Element: " + srcEl.nodeName + "#" + srcEl.id);
  }
  this.classList.add("selected");
}

function dragOver(e){
  e.preventDefault();
  log("Drag Over: " + e.target.nodeName + (e.target.id != "" ? "#" + 

e.target.id : ""));
  return false;
}

function dragLeave(e){
  log("Drag Leave: " + e.target.nodeName + (e.target.id != "" ? "#" + 

e.target.id : ""));
}

function dragStop(e){
  log("Drag End: " + e.target.nodeName + "#" + e.target.id);
  this.classList.remove("selected");
}

log("Init");

var item = document.getElementById("draggable");
item.addEventListener('dragstart', dragStart, false);
item.addEventListener('dragover', dragOver, false);
item.addEventListener('dragleave', dragLeave, false);
window.addEventListener('dragleave', dragLeave, false);
var items = document.querySelectorAll('.items > div');
[].forEach.call(items, function(el) {
  el.addEventListener('dragover', dragOver, false);
});
</script>
</body>
</html>

Как видите, здесь используется необработанный JavaScript. Я возился с пользовательским интерфейсом jQuery и сохранил таблицу стилей только для удобства создания тем. У нас есть раздел для распечатки сведений журнала, перетаскиваемый и статический элемент.

winb-1.htm

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Window B</title>
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <style>
.drag-item {
  width: 100px;
  height: 100px;
  background-color: red;
}

body {
  position: relative;
}

div.drag-helper {
  width: 100px;
  height: 100px;
  background-color: red;
  z-index: 1002;
  position: relative;
}

#log {
  width: 100%;
  height: 5em;
  line-height: 1em;
  font-size: 1em;
  overflow-y: auto;
}

#dropzone {
  background-color: green;
  width: 95%;
  height: 340px;
}
  </style>
</head>
<body>
  <pre id="log"></pre>
  <div id="dropzone"></div>
<script>
jQuery(function($) {
  function log(s){
    var now = new Date();
    var t = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds

() + "." + now.getMilliseconds();
    $("#log").append(t + ": " + s + "\r\n").scrollTop($("#log").prop

("scrollHeight"));
  }

  function dragEnter(e){
    e.preventDefault();
    log("Drag Enter triggered: " + $(e.target).prop("nodeName") + 

($(e.target).attr("id").length ? "#" + $(e.target).attr("id") : ""));
  }

  function dragOver(e){
    log("Drag Over triggered: " + $(e.target).prop("nodeName") + 

($(e.target).attr("id").length ? "#" + $(e.target).attr("id") : ""));
    e.dataTransfer.dropEffect = 'move';
    e.preventDefault();
  }

  function handleDrop(e){
    if (e.stopPropagation) {
      e.stopPropagation();
    }
    log("Drop Triggered: " + $(e.target).attr("id"));
    return false;
  }

  function dragEnd(e){
    log("Drag End Triggered: " + $(e.target).prop("nodeName") + 

($(e.target).attr("id").length ? "#" + $(e.target).attr("id") : ""));
  }

  log("Init");

  $("#dropzone").on({
    dragenter: dragEnter,
    dragover: dragOver,
    drop: handleDrop,
    mouseup: handleDrop,
    dragend: dragEnd
  });

  $(window).on({
    dragenter: dragEnter,
    dragover: dragOver,
    drop: handleDrop,
    dragend: dragEnd
  });

});
</script>
</body>
</html>

Окно B использует jQuery, так как целью было преобразовать элемент в jQuery UI Draggable.

Первое, что нужно знать, это невозможно сделать в пути. Поскольку элемент Source не является частью целевого DOM, это невозможно сделать. Его можно добавить и инициализировать как Draggable в событии drop. По сути, произойдет следующее: в это время будет создан новый элемент, которому будут назначены все данные.

Во-вторых, передача данных ненадежна, и я бы не стал использовать DataTransfer в качестве контейнера данных. Я бы посоветовал использовать localStorage. Это похоже на файл cookie и намного надежнее.

Например, я создал следующий объект данных:

{
  id,
  type,
  attr: {
    id,
    class,
    width,
    height
  },
  content
}

Вот несколько примеров функций:

function collectData(obj){
  return {
    id: obj.attr("id"),
    type: obj.prop("nodeName"),
    attr: {
      id: obj.attr("id"),
      class: obj.attr("class"),
      width: obj.width(),
      height: obj.height()
    },
    content: obj.text().trim()
  };
}

function saveData(k, d){
  localStorage.setItem(k, JSON.stringify(d));
}

function getData(k){
  return JSON.parse(localStorage.getItem(k));
}

function makeEl(d, pObj){
  return $("<" + d.type +">", d.attr).html("<p>" + d.content + "</p>").appendTo(pObj);
}

$("#draggable").on('dragstart', function(e){
  saveData("drag-data", collectData($(this)));
});

$("#dropzone").on('drop', function(e){
  var item = makeEl(getData('drag-data'), $(this));
  item.addClass("clone").position({
    my: "center",
    of: e
  }).draggable();
});

По идее все это должно работать. На практике я столкнулся с массой препятствий. Я бы предложил что-то вроде действия «нажми и копируй». Когда пользователь щелкает элемент в окне A (выбирая его), а затем щелкает там, где он хочет, в окне B. Опять же, используя localStorage, элемент может быть клонирован в новое место.

wina-3.htm

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Draggable - Default functionality</title>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <style>
  .items {
    position: relative;
  }
  .items > div {
    margin-right: 5px;
    width: 150px;
    height: 150px;
    padding: 0.5em;
    border-radius: 6px;
    display: inline-block;
  }
  #log {
    width: 100%;
    height: 5em;
    overflow-y: auto;
  }
  [draggable].idle {
    background-color: rgba(255,0,0,0.5); 
  }
  [draggable].selected {
    background-color: rgba(255,0,0,0.95);
  }
  </style>
</head>
<body>
<pre id="log"></pre>
<div class="items ui-widget">
  <div id="draggable" class="ui-widget-content idle" draggable="true">
    <p>Click on me</p>
  </div>
  <div id="static" class="ui-widget-content">
    <p>I can't be moved</p>
  </div>
</div>
<script>
var intv;

function log(s){
  var now = new Date();
  var t = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "." + now.getMilliseconds();
  var l = document.getElementById("log");
  l.append(t + ": " + s + "\r\n");
  l.scrollTop = l.scrollHeight;
}

function collectData(el){
  return {
    id: el.id,
    type: el.nodeName,
    attr: {
      id: el.id,
      class: el.className,
      width: el.width,
      height: el.height
    },
    content: el.innerText
  };
}

function saveData(k, v){
  localStorage.setItem(k, JSON.stringify(v));
}

function getData(k){
  return JSON.parse(localStorage.getItem(k));
}

function clearData(k){
  localStorage.setItem(k, null);
}

function selElem(e){
  var trg = e.target.nodeName + (e.target.id != "" ? "#" + e.target.id : "");
  if(e.target.classList.contains("selected")){
    log("Deselect element: " + trg);
    e.target.classList.remove("selected");
  } else {
    log("Element Selected: " + trg);
    e.target.classList.add("selected");
    saveData("select-data", collectData(e.target));
  }
  intv = setInterval(function(){
    if(getData("select-data") == null){
      document.getElementsByClassName("selected")[0].classList.remove("selected");
      log("Unselected");
      clearInterval(intv);
    }
  }, 1000);
}

log("Init");

var item = document.getElementById("draggable");
item.addEventListener('click', selElem);
</script>
</body>
</html>

winb-3.htm

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Window B</title>
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <style>
.drag-item {
  width: 100px;
  height: 100px;
  background-color: red;
}

body {
  position: relative;
}

#log {
  width: 100%;
  height: 5em;
  line-height: 1em;
  font-size: 1em;
  overflow-y: auto;
}

#dropzone {
  background-color: green;
  width: 95%;
  height: 340px;
  position: relative;
}

.cloned {
  position: absolute;
  width: 150px;
  height: 150px;
  padding: 0.5em;
  border-radius: 6px;
  display: inline-block;
  background-color: rgba(255,0,0,0.75);
}
  </style>
</head>
<body>
  <pre id="log"></pre>
  <div id="dropzone"></div>
<script>
jQuery(function($) {
  function log(s){
    var now = new Date();
    var t = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds

() + "." + now.getMilliseconds();
    $("#log").append(t + ": " + s + "\r\n").scrollTop($("#log").prop

("scrollHeight"));
  }

  function getData(k){
    console.log("Getting Data: '" + k + "'", localStorage.getItem(k));
    return JSON.parse(localStorage.getItem(k));
  }

  function clearData(k){
    log("Clear Data");
    localStorage.setItem(k, null);
  }

  function makeEl(dObj, pObj){
    console.log(dObj, pObj);
    return $("<" + dObj.type + ">", dObj.attr).html("<p>" + dObj.content + 

"</p>").appendTo(pObj);
  }

  function handleDrop(e){
    if (e.stopPropagation) {
      e.stopPropagation();
    }
    var trg = $(e.target);
    log("Drop Triggered: " + trg.prop("nodeName") + "#" + trg.attr("id"));
    var d, item;
    if(e.target.id == "dropzone" && (e.type == "click" || e.type == 

"mouseup")){
      log("Click Detected - Collecting Data");
      d = getData("select-data");
      console.log("Data", d);
      d.attr.id = "clone-" + ($("#dropzone .cloned").length + 1);
      log("Making Element: " + d.type + "#" + d.attr.id);
      item = makeEl(d, trg);
      item.removeClass("selected").addClass("cloned").position({
        my: "center",
        of: e
      }).draggable();
      clearData("select-data");
      return true;
    }
    return false;
  }

  log("Init");

  $("#dropzone").on({
    mouseup: handleDrop,
    click: handleDrop
  });
});
</script>
</body>
</html>

Я знаю, что это не тот ответ, который вы ищете, и для этого вам нужно попытаться задать настоящий вопрос. Вы, кажется, постоянно задаете вопрос.

Надеюсь это поможет.

person Twisty    schedule 24.06.2019