[英]HTML5 DnD - Why is ghost image only working as expected AFTER dragging & dropping an element?
I'm trying to get a p
element with a nested img
to show as the ghost image when dragging.我试图让一个带有嵌套
img
的p
元素在拖动时显示为重影图像。
I'm not sure how to debug this but I have noticed that once the images are cached or have been dragged and dropped somewhere on the page, it works as expected.我不确定如何调试它,但我注意到一旦图像被缓存或被拖放到页面上的某个位置,它就会按预期工作。 I've made a MWE here:
我在这里做了一个 MWE:
The smiley face is dragged on first load of the page and shows the erroneous behavior - the emoji doesn't show during the drag.笑脸在页面首次加载时被拖动并显示错误行为 - 表情符号在拖动过程中不显示。 The sad face is dragged, released, and then redragged, which results in the expected behavior - the emoji does show as part of the ghost image.
悲伤的脸被拖动,释放,然后重新拖动,这导致了预期的行为 - 表情符号确实显示为幽灵图像的一部分。 This is true of all the images.
所有图像都是如此。
What I've tried: I thought it might be an issue with the way the page elements are loaded, so I moved the javascript to the bottom of the body (trying to ensure all elements are loaded before the script runs).我试过的:我认为这可能是页面元素加载方式的问题,所以我将 javascript 移动到正文的底部(试图确保在脚本运行之前加载所有元素)。 This doesn't solve the issue.
这并不能解决问题。
MWE code: I got the emojis from here , but I guess any pngs you have lying around on your machine will do to reproduce this. MWE 代码:我从这里得到了表情符号,但我想你机器上的任何 png 都可以重现这个。
index.php:索引.php:
<html>
<head>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body>
<h2>Order these items</h2>
<div id="main_wrapper">
<?php
$json = json_decode(file_get_contents("image_set.json"), true);
echo '<div id="home_container" ondrop="drop(event, this)" ondragover="allowDrop(event)">';
$i = 0;
foreach($json as $k => $v) {
echo '<p class="drag_item" draggable="true" ondragstart="drag(event)" id="drag'.$i.'"><img draggable="false" src="/images/'.$v['fn'].'" width=200 height=200>'.$v['text'].'</p>';
$i++;
}
echo '</div>';
?>
<div id="buffer" style="min-height:100px; width:100%;"></div>
<div id="dropzone_wrapper">
<?php
for($i = 0; $i < count($json); $i++) {
echo '<div class="dropzone" id="dropzone'.$i.'" ondrop="drop(event, this)" ondragover="allowDrop(event)"></div>';
if($i < count($json)-1){echo '<';}
}
?>
</div>
<div id="msg"></div>
</div>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
var dataList = ev.dataTransfer.items;
dataList.add(ev.target.id, "text/plain");
}
function drop(ev, el) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
var element_to_drop = document.getElementById(data);
let droppable = true;
// If the dropzone already contains something (not text due to
// spaces in markup being counted as text), don't allow
// another drop to occur.
if (el.childNodes.length > 0) {
el.childNodes.forEach(function(obj) {
if(obj.nodeName != '#text') {
droppable = false;
}
});
}
if(droppable)
el.appendChild(document.getElementById(data));
}
function reset() {
// Put all drag items back into the home container
let home = document.getElementById('home_container');
let cards = document.querySelectorAll('.drag_item');
for(var i = 0; i < cards.length; i++) {
home.appendChild(cards[i]);
}
}
</script>
</body>
</html>
image_set.json: image_set.json:
{
"happy": {
"fn":"happy.png",
"text":"A happy face"
},
"sad": {
"fn":"sad.png",
"text":"A sad face"
},
"angry": {
"fn":"angry.png",
"text":"An angry face"
},
"confused": {
"fn":"confused.png",
"text":"A confused face"
},
"sleepy": {
"fn":"sleepy.png",
"text":"A sleepy face"
}
}
stylesheet.css:样式表.css:
* {
box-sizing:border-box;
padding:0px;
margin:0px;
font-family:sans-serif;
font-weight:100;
}
body {
padding:20px;
}
h2 {
padding:20px 0;
font-size:4em;
}
p.drag_item {
text-align:center;
transition:0.5s;
width:200px;
height:200px;
}
.drag_item:hover {
cursor:move;
}
#home_container, #dropzone_wrapper {
min-height:200px;
width:100%;
display:flex;
flex-direction:row;
justify-content:space-around;
margin:20px 0;
align-items:center;
}
#dropzone_wrapper {
font-size:3em;
}
#dropzone_wrapper p {
font-size:initial;
}
#home_container {
border:1px solid black;
border-radius:8px;
background-color:#e5e5e5;
}
#home_container p {
width:200px;
font-size:16px;
}
#msg {
display:block;
font-size:2.5em;
}
.dropzone {
min-height:200px;
width:200px;
border:1px dashed black;
background-color:#00a8bd;
}
I've done a bit research to find the problem.我做了一些研究来找到问题所在。 This was a bit hard for me, because Firefox was the only browser where the ghost image was not shown on the first load of the page and the first drag.
这对我来说有点难,因为 Firefox 是唯一一个在第一次加载页面和第一次拖动时没有显示重影图像的浏览器。 I opened the
Network
tab and found out that the image is only requested on the first drag (which I don't really understand, because the images were completely loaded).我打开
Network
选项卡,发现仅在第一次拖动时才请求图像(我不太明白,因为图像已完全加载)。
Anyways, I finally I managed to get this to work, by changing the draggable element to the image instead of the paragraph.无论如何,我终于设法让这个工作,通过将可拖动元素更改为图像而不是段落。
index.php:索引.php:
<div id="main_wrapper">
<?php
$json = json_decode(file_get_contents("image_set.json"), true);
echo '<div id="home_container" ondrop="drop(event, this)" ondragover="allowDrop(event)">';
$i = 0;
foreach($json as $k => $v) {
echo '<p class="drag_item"><img ondragstart="drag(event)" id="drag'.$i.'" draggable="true" src="images/'.$v['fn'].'" width=200 height=200>'.$v['text'].'</p>';
$i++;
}
echo '</div>';
?>
<div id="buffer" style="min-height:100px; width:100%;"></div>
<div id="dropzone_wrapper">
<?php
for($i = 0; $i < count($json); $i++) {
echo '<div class="dropzone" id="dropzone'.$i.'" ondrop="drop(event, this)" ondragover="allowDrop(event)"></div>';
if($i < count($json)-1){echo '<';}
}
?>
</div>
<div id="msg"></div>
</div>
JS: JS:
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
// get the cursor position relative to the element
var x = (ev.pageX - ev.target.offsetLeft) + document.body.scrollLeft;
var y = (ev.pageY - ev.target.offsetTop) + document.body.scrollTop;
ev.dataTransfer.setData("text", ev.target.id);
// set the parent element (the paragraph) as the custom ghost image and set the position of the ghost image (x, y)
ev.dataTransfer.setDragImage(ev.target.parentElement, x, y);
}
function drop(ev, el) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
var element_to_drop = document.getElementById(data);
let droppable = true;
if (el.childNodes.length > 0) {
el.childNodes.forEach(function(obj) {
if(obj.nodeName != '#text') {
droppable = false;
}
});
}
if(droppable)
el.appendChild(document.getElementById(data).parentElement);
}
function reset() {
let home = document.getElementById('home_container');
let cards = document.querySelectorAll('.drag_item');
for(var i = 0; i < cards.length; i++) {
home.appendChild(cards[i]);
}
}
This works pretty well in: Chrome, Edge, IE 11
这适用于:Chrome、Edge、IE 11
NOTE: This only works perfectly in Firefox (the paragraph text only appears in this browser)
注意:这仅在 Firefox 中完美运行(段落文本仅出现在此浏览器中)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.