javascript - jQuery Draggable - 在 html5 原生 Drag And Drop api 事件上创建可拖动并开始拖动
问题描述
好的,基本上我想要实现的是,当一个dragover
事件从.HTML5 Drag And Drop API
draggable
dragend
HTML5 Drag And Drop API
我想这样做的原因如下:
- 我有一个使用插件的应用程序,它具有依赖于
jQuery.ui draggable
to 功能的功能(它是FullCalendar Scheduler
插件,版本 3) - 我想在应用程序中实现一个新功能,客户端可以使用它从浏览器窗口 A中拖动一些东西,并将其拖放到浏览器窗口 B中的上述插件中。
- 由于上述插件不适用于 native
HTML5 Drag and Drop API
,并且jQuery.ui draggable
无法将元素从一个浏览器窗口拖动到另一个浏览器窗口,我认为我唯一的选择是将这两个插件混合使用。
我对这个问题提出的解决方案是,使用 native HTML5 Drag and Drop API
,当拖动元素到达 a 时,在浏览器窗口 Bdropzone
中创建一个新的可拖动元素,并在其上模拟一个事件,因此它开始跟随光标。当事件触发时,我计划简单地在元素上触发事件,从这里开始,调度程序插件可以做到这一点。mousedown
dragend
mouseup
draggable
为了尝试对此进行测试,首先使用单个浏览器窗口,我尝试实现上述解决方案的第一部分,即:当dragover
触发时,创建jQuery.ui draggable
并模拟mousedown
它,然后它应该开始跟随鼠标. 我无法实现这种行为。
我做了一个小提琴,在那里你可以看到我到目前为止尝试过的东西(我没有在这里发布整个代码,因为它相当长):JSFiddle
基本上,我在 Fiddle 上遇到的错误,我尝试了这两个选项,都是一个type.indexOf is not a function
错误。
我还就以下问题询问并获得了一些帮助,建议的解决方案在使用事件启动拖动操作时click
可以正常工作,但它不适用于任何其他事件类型。mousedown.draggable
我强调,我只能从 a模拟一个事件,MouseEvent
而该dragend
事件不是 a MouseEvent
。
长话短说,我需要帮助才能获得我正在寻找的结果,至少对于我提出的解决方案的第一部分!
解决方案
对此似乎没有一个好的答案。首先,并非所有浏览器都支持相同的 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 UI,我保留样式表只是为了方便主题化。我们有一个部分用于打印日志详细信息、一个可拖动项和一个静态项。
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 的一部分,因此无法完成。它可以在drop
事件中添加并初始化为 Draggable。基本上会发生的事情是在分配所有数据的时候创建一个新元素。
其次,数据传输不可靠,我会避免将 DataTransfer 作为您的数据容器。我建议使用 localStorage。这类似于 cookie,并且更可靠。
例如,我创建了以下 Data 对象:
{
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>
我知道这不是您要寻找的答案,为此您需要尝试提出真正的问题。你似乎一直在问这个问题。
希望这可以帮助。
推荐阅读
- excel - 获取日期范围 VBA 之间的所有月份和年份
- machine-learning - 计算成本低廉的图像分类器
- javascript - 如何打印多个订单的运输标签
- google-cloud-platform - 如何处理 Google Cloud Run 中的长请求?
- javascript - 无法在纸质列表框聚合物 3 中获取多选值
- reactjs - 如何使用我的 react 组件 PlaceInput 实现菜单输入框中的位置自动补全?
- c - 在链表的链表中插入元素
- java - 我如何与其他人分享 klov 报告?
- arrays - 比较 beanshell 中的 3 个数组并得到 1 个数组
- database-design - “仅当分区键受 EQ 或 IN 限制时,才支持 ORDER BY。” 卡桑德拉