我有一些元素想要拖到画布上以在之后返回它们的坐标。 所以元素应该彼此相邻出现,而不是我将能够拖动它们。 我面临的问题是元素彼此之间没有空格分隔:
我正在使用 https://www.w3schools.com/howto/howto_js_draggable.asp 中的函数 dragElement(element)
使我的元素可拖动。
//Make the DIV element draggagle:
dragElement(document.getElementById("mydiv"));
dragElement(document.getElementById("mydiv2"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<div class="container">
<div id="markers" class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
我尝试将 CSS 位置属性从绝对更改为相对,它使元素设置为彼此相邻,但我无法再拖动它们。
在我发布的代码中,我只有两个元素,但实际上,将使用 JS 代码动态创建更多新元素。
这是我的 JS 代码:
//this list will be uploaded by the user
var d = ["module1", "module2",.......,"module22"];
for(i in d){
append_module_name_to_drag_div(d[i]);
dragElement(document.getElementById(d[i]));
}
function append_module_name_to_drag_div(module_name){
var mydiv = document.createElement("div");
mydiv.id=module_name;
mydiv.className ='col-sm-10';
var mydivmarker= document.createElement("div");
mydivmarker.id=module_name+"header";
mydivmarker.className ='mydivheader';
var marker_image = new Image();
marker_image.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png";
marker_image.height = 45;
marker_image.width = 35;
mydivmarker.append(marker_image);
mydiv.innerHTML=module_name;
mydiv.append(mydivmarker);
document.getElementById("markers").appendChild(mydiv);
}
答案 0 :(得分:0)
您可以像链接的 w3schools 示例中提到的那样使用 position: absolute
,但无需为绝对定位的元素定义 top
、left
等,它们都具有相同的默认值:{{1 }} 和 top: 0
。因此它们都出现在同一个位置,从而导致彼此堆叠。
如果为每个绝对定位的元素为 left: 0
、top
等定义不同的值,则可以防止堆叠。例如:
left
这是针对您最初发布的问题的解决方案,其中包含两个硬编码的可拖动元素,但它不太适合动态添加的内容。
工作示例:
为简单起见,我省略了函数 #mydiv2 {
top: 170px;
}
中的第一个 if ... else
块,并将事件侦听器直接附加到整个元素:
dragElement()
elmnt.onmousedown = dragMouseDown;
//Make the DIV element draggagle:
dragElement(document.getElementById("mydiv2"));
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
position :absolute;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
cursor: move;
border: 1px solid #d3d3d3;
}
#mydiv2 {
top: 170px;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<div class="container">
<div class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
对于动态添加的内容(或任何其他不使用 transform: translate()
、top
等的原因),最好使用 left
并省略 transform: translate()
,以便元素保持原样,无法堆叠。
要使其发挥作用,您只需从旧的 position: absolute
值中减去原始计算值,然后用该减法的值覆盖该值(以保存它们以供下一次函数调用):
translate
最后,您必须将发生样式的两行从 pos1 = pos1 - (pos3 - e.clientX);
pos2 = pos2 - (pos4 - e.clientY);
和 top
更改为带有 left
的一行:
translate
工作示例:
我将过时的 elmnt.style.transform = 'translate(' + (pos1) + "px, " + (pos2) + "px)";
换成了 var
,因为变量会改变。
let
//Make the DIV element draggagle:
dragElement(document.getElementById("mydiv2"));
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos1 - (pos3 - e.clientX);
pos2 = pos2 - (pos4 - e.clientY);
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.transform = 'translate(' + (pos1) + "px, " + (pos2) + "px)";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
width: 160px;
background-color: #f1f1f1;
text-align: center;
cursor: move;
border: 1px solid #d3d3d3;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
w3schools 示例 <div class="container">
<div class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
中变量的名称不是很直观。因此,应将它们重命名以易于理解它们的用途:pos1, pos2, pos3, pos4
和 translate = { x: 0, y: 0 }
。
工作示例:
client = { x: 0, y: 0 }
//Make the DIV element draggagle:
dragElement(document.getElementById("mydiv2"));
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
let translate = { x: 0, y: 0 };
let client = { x: 0, y: 0 };
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
client.x = e.clientX;
client.y = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
translate.x = translate.x - (client.x - e.clientX);
translate.y = translate.y - (client.y - e.clientY);
client.x = e.clientX;
client.y = e.clientY;
// set the element's new position:
elmnt.style.transform = 'translate(' + (translate.x) + "px, " + (translate.y) + "px)";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
width: 160px;
border: 1px solid #d3d3d3;
text-align: center;
cursor: move;
background-color: #f1f1f1;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
为了演示您稍后添加的用于动态添加可拖动元素的函数的代码,这里是最终实现。我将过时的 <div class="container">
<div class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
与 var
交换,因为变量不会改变。
工作示例:
const
const d = ["module1", "module2", "module3", "module4", "module5"];
for(i in d) {
append_module_name_to_drag_div(d[i]);
dragElement(document.getElementById(d[i]));
}
function append_module_name_to_drag_div(module_name) {
const mydiv = document.createElement("div");
mydiv.id = module_name;
mydiv.className = 'module col-sm-10';
const mydivmarker = document.createElement("div");
mydivmarker.id = module_name+"header";
mydivmarker.className = 'mydivheader';
const marker_image = new Image();
marker_image.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png";
marker_image.height = 45;
marker_image.width = 35;
mydivmarker.append(marker_image);
mydiv.innerHTML = module_name;
mydiv.append(mydivmarker);
document.getElementById("markers").appendChild(mydiv);
}
function dragElement(elmnt) {
let translate = { x: 0, y: 0 };
let client = { x: 0, y: 0 };
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
client.x = e.clientX;
client.y = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
translate.x = translate.x - (client.x - e.clientX);
translate.y = translate.y - (client.y - e.clientY);
client.x = e.clientX;
client.y = e.clientY;
// set the element's new position:
elmnt.style.transform = 'translate(' + (translate.x) + "px, " + (translate.y) + "px)";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
.module {
width: 80px;
border: 1px solid #d3d3d3;
text-align: center;
cursor: move;
background-color: #f1f1f1;
}
.mydivheader {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
答案 1 :(得分:0)
元素出现在彼此的顶部是因为您的 #mydiv
声明了 position: absolute
,这将其从文档流中移除。流出的元素将被放置在流动元素的顶部,由 CSS 指定。
Greg 建议使用 CSS 函数 translate()
进行移动,而不是使用 position: absolute
和 top
等。这会使元素留在流中,这意味着它们将还在考虑中。
由于 translate()
会在重排(重新验证文档流)后生效,因此即使可拖动元素被移动,它也不会干扰您的布局。
如果您只对结果感兴趣,请跳过。但这里有更多信息。
W3Schools 因有些过时或有时甚至提供糟糕的建议而臭名昭著,所以我建议在阅读他们的文章的基础上做一些研究。< /p>
现在,W3Schools' dragElement()
函数非常适合向后兼容,因为它是为 2011 年及更早版本的浏览器编写的。如今,大多数(如果不是全部)浏览器都实现了 HTML5、CSS3 和(至少)ES6(JavaScript 规范),以及某些浏览器标准。
这意味着将支持以下(以及更多!):
const
/let
的使用。var
之间的区别:它们声明块范围变量,并且不会被提升。但是,使用它们将使调试更容易,并会传达以下信息:
const
表示引用永远不会改变。let
表示引用可能被更改。Element.querySelector()
搜索元素的后代。 (类似于Document.querySelector()
。)addEventListener()
/removeEventListener()
的使用。onevent
-listeners 时元素的一个事件侦听器。一些题外话:
首先,我将删除所有先前存在的评论,以便新评论可以解释更改。
对于字符串,有些人更喜欢 '
(单引号)而不是 "
(双引号),因为您更可能希望使用 "
而不是 {{1} } 在一个字符串中。使用一个允许不转义使用另一个。
我更喜欢 JS 中的 '
,所以不要对我的更改使用它们的原因感到困惑。
我将 '
的所有实例替换为 var
或 const
,具体取决于哪个看起来更合适。
代码现在将使用 let
/addEventListener()
而不是 removeEventListener()
-listener。
最重要的变化:
onevent
-classdraggable
<header>
,请将其设为 <header>
<section>
-class 添加规则draggable
也是 draggable
时添加 enabling CSS rule(s)<section>
、xPos
代替 yPos
、pos0
、pos1
、pos2
MouseEvent.movementX
(和 pos3
)更新位置值Element.styles.transform
和 .movementY
更新屏幕位置translate()
// Make all `.draggable` draggable
for (const el of document.querySelectorAll('.draggable'))
dragElement(el);
// May be changed? Hence `let`
let d = ["module1", "module2", "module22"];
// Changed loop to for...of, because we only want to iterate over the array-elements
for (const el of d) {
append_module_name_to_drag_div(el);
dragElement(document.getElementById(el));
}
function append_module_name_to_drag_div(module_name){
const mydiv = document.createElement("div");
mydiv.id = module_name;
mydiv.className = 'col-sm-10 draggable'; // Added '.draggable'
const mydivmarker = document.createElement("div");
const marker_image = new Image();
marker_image.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png";
marker_image.height = 45;
marker_image.width = 35;
mydivmarker.append(marker_image);
// Generally bad to use .innerHTML with user-generated content.
// Prefer .innerText or .textContent.
// Read more on:
// https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations
mydiv.innerText = module_name;
mydiv.append(mydivmarker);
// Changed to .append(), try to stay consistent!
// I suggest using .append() over .appendChild(), as the former allows
// an arbitrary amount of arguments.
document.getElementById("markers").append(mydiv);
}
// Originally from: "How to create a draggable HTML element" - W3Schools
// ( https://www.w3schools.com/howto/howto_js_draggable.asp )
function dragElement(el) {
// We'll only need x- and y-positions; may/will change, hence `let`
let xPos = 0;
let yPos = 0;
if (el.querySelector('header')) // Use Element.querySelector() to avoid using unnecessary IDs
el.querySelector('header').addEventListener('mousedown', dragMouseDown);
else
el.addEventListener('mousedown', dragMouseDown);
function dragMouseDown(event) {
// The event-object will always be passed; no need to refer to window.event
event.preventDefault();
// No need to save initial mouse-position
document.addEventListener('mouseup', closeDragElement);
document.addEventListener('mousemove', elementDrag);
}
function elementDrag(event) {
event.preventDefault();
// New positions calculated using MouseEvent.(movementX|movementY)
xPos += event.movementX;
yPos += event.movementY;
// Set position as translate() of .style.transform
el.style.transform = `translate(${xPos}px, ${yPos}px)`;
}
function closeDragElement() {
document.removeEventListener('mouseup', closeDragElement);
document.removeEventListener('mousemove', elementDrag);
}
}
/* Add enabling CSS for .draggable */
/* Enabling CSS:
* Only declare properties when rules apply.
*/
/* Disabling CSS:
* Declare all "default" properties.
* Reset all then-unwanted properties.
* May overwrite other rule's declarations in the process.
*/
/* Related: https://www.silvestar.codes/articles/you-want-a-single-enabling-selector-not-the-one-that-disables-the-rule-of-the-previous-one/ */
.draggable {width: fit-content} /* Default */
.draggable:not(section) {cursor: move} /* Enabling CSS */
section.draggable {
border: 1px solid #d3d3d3;
text-align: center;
background-color: #f1f1f1;
}
section.draggable>header {
padding: .625rem;
color: #fff;
background-color: #2196F3;
cursor: move;
}
答案 2 :(得分:0)
我发现的最好方法是每次都为每个元素设置 top
和 left
,这将使每个元素处于单独的位置而不会破坏可抓取的部分:
const d = ["module1", "module2", "module3", "module4", "module5"];
for(i in d){
append_module_name_to_drag_div(d[i],top,left);
dragElement(document.getElementById(d[i]));
if(left<220){left=left+39;}
//you can set here height and width: in my case 300 was the width of the container, 35 was the width of markers
else{
left=5;
top=top+70;//70 height of marker
}
}
我修改了这个函数,增加了两个参数来指定顶部和左侧:
function append_module_name_to_drag_div(module_name,top,left){
var mydiv = document.createElement("div");
mydiv.id=module_name;
mydiv.className ='col-sm-10';// 'col-md-3 col-lg-3 col-xl-3 col-sm-6';//'mydiv';
var mydivmarker= document.createElement("div");
mydivmarker.id=module_name+"header";
mydivmarker.className ='mydivheader';// 'col-sm-4';//'mydivheader';
var marker_image = new Image();
marker_image.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png";
marker_image.height = 45;
marker_image.width = 35;
mydivmarker.append(marker_image);
// var p = document.createElement("p");
mydiv.innerHTML=module_name;
// mydiv.append(p);
mydiv.append(mydivmarker);
///***
// mydiv.style.cssFloat = "left";
mydiv.style.left = left.toString()+"px";
mydiv.style.top = top.toString()+"px";
///**** */
document.getElementById("markers").appendChild(mydiv);
var linebreak = document.createElement("br");
document.getElementById("markers").appendChild(linebreak);
}
W3Schools 的函数除了两行 where(//set the element's new position:)
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
/* if present, the header is where you move the DIV from:*/
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
/* otherwise, move the DIV from anywhere inside the DIV:*/
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
/* stop moving when mouse button is released:*/
document.onmouseup = null;
document.onmousemove = null;
}
}