简体   繁体   English

为什么我的 forloop 和 querySelectorAll 不能与同一类的多个 div 一起使用?

[英]Why does my forloop and querySelectorAll dont work with multiple div's of the same class?

Basically I'm trying to make multiple draggable div's with a script.基本上我正在尝试使用脚本制作多个可拖动的 div。 It works fine for 1 div like this:它适用于这样的 1 个 div:

https://jsfiddle.net/werwer/3zvqm2sa/1/ https://jsfiddle.net/werwer/3zvqm2sa/1/

where I have aquerySelector that gets one class name.我有一个获取一个类名的querySelector。

I wish to make multiple draggable divs, sort of like a windows computer.我希望制作多个可拖动的 div,有点像 Windows 计算机。 So used a querySelectorAll, put my eventListeners into a forloop to loop through the array, and selected the array item one by one like this:于是用了一个querySelectorAll,把我的eventListeners放到一个forloop中循环遍历数组,像这样一一选中数组项:

https://jsfiddle.net/werwer/0n5eLmfv/11/ https://jsfiddle.net/werwer/0n5eLmfv/11/

It completely removed the ability to move all the divs (including the one that originally can move).它完全消除了移动所有 div 的能力(包括最初可以移动的 div)。 So I placed a console.log to check if my mouse up and down works for both divs.所以我放置了一个console.log 来检查我的鼠标上下是否适用于两个div。 Here's the fun part: the mouseup and down check worked for the original black div (the one that supposedly can move), but could only detect mouse up for the new white div.这是有趣的部分:mouseup 和 down 检查适用于原始的黑色 div(据说可以移动的那个),但只能检测到新的白色 div 的 mouse up。 So I'm not exactly sure what is going on.所以我不确定发生了什么。

 var wrapper = document.querySelectorAll(".panel"); for (i = 0; i < wrapper.length - 1; i++) { /* multiple event listeners for mouse up and down */ wrapper[i].addEventListener("mousedown", () => { wrapper[i].classList.add("active"); wrapper[i].addEventListener("mousemove", onDrag); console.log("check mouse down"); /* checking mouse down */ }); document.addEventListener("mouseup", () => { wrapper[i].classList.remove("active"); wrapper[i].removeEventListener("mousemove", onDrag); console.log("check mouse up"); /* checking mouse down */ }); } /* what moves the divs */ function onDrag({ movementX, movementY }) { let getStyle = window.getComputedStyle(wrapper); let leftVal = parseInt(getStyle.left); let topVal = parseInt(getStyle.top); wrapper.style.left = `${leftVal + movementX}px`; wrapper.style.top = `${topVal + movementY}px`; }
 .projects { display: flex; width: 100%; height: 125vh; background-image: url(images/laptop.png); background-position: 100%; background-position-y: center; background-position-x: center; background-size: 95%; background-repeat: no-repeat; } .gamedev-panel { position: absolute; top: 3rem; left: 16rem; width: 40rem; height: 30rem; background-color: #403d39; } .gamedev-titlebar { height: 3rem; background: #EB5E28; display: flex; align-items: center; justify-content: right; } .btn-1 { background: turquoise; } .btn-2 { background: yellow; } .btn-3 { background: red; } .game-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-right: 1rem; } .gamedev-heading { background: none; position: absolute; /* width: 369.43px; height: 40.32px; left: 408.26px; top: 2592.77px; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #CCC5B9; pointer-events: none; } .gamedev-gif { position: absolute; bottom: 1rem; right: 1rem; pointer-events: none; } .webdev-panel { position: absolute; top: 1rem; right: 16rem; width: 25rem; height: 30rem; background-color: #fffcf2; display: inline-flex; justify-content: flex-end; overflow: hidden; } .webdev-titlebar { /* position: absolute; */ height: 30rem; width: 3rem; background: #EB5E28; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; pointer-events: none; } .web-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-top: 1rem; /* margin-right: 1rem; */ pointer-events: none; } .webdev-heading { background: none; /* position: absolute; right: 5rem; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #252422; pointer-events: none; } .webdev-content { margin-right: 1rem; pointer-events: none; } .webdev-img { width: 80%; height: 80%; position: absolute; right: 4rem; top: 5rem; pointer-events: none;
 <div class="projects"> <div class="gamedev-panel panel"> <div class="gamedev-titlebar"> <div class="btn-1 game-btn"></div> <div class="btn-2 game-btn"></div> <div class="btn-3 game-btn"></div> </div> <h2 class="gamedev-heading">I DEVELOP GAMES</h2> <img src="images/game.gif" alt="" class="gamedev-gif"> </div> <div class="webdev-panel panel"> <div class="webdev-content"> <h2 class="webdev-heading">I MAKE WEBSITES</h2> <img src="images/web.png" alt="" class="webdev-img"> </div> <div class="webdev-titlebar"> <div class="btn-1 web-btn"></div> <div class="btn-2 web-btn"></div> <div class="btn-3 web-btn"></div> </div> </div> <div class="others-panel"></div> </div>

Please delegate请委托

Here is an untested version since I am not on a proper device, but it gives the structure这是一个未经测试的版本,因为我不在合适的设备上,但它给出了结构

In the onDrag we just test the active element if there is none, we could leave, but as I said, I cannot actually test this to conclusion在 onDrag 中,我们只测试活动元素,如果没有,我们可以离开,但正如我所说,我实际上无法对此进行测试得出结论

I use the same eventlistener for mouseup and down and then instead of add or remove I toggle active depending on the event.我对 mouseup 和 down 使用相同的事件侦听器,然后根据事件而不是添加或删除,我切换为活动状态。 If mousedown, add active if up remove active (that is what toggle does)如果 mousedown,则添加 active if up remove active(这就是切换的作用)

I add the event listeners to the OUTER div, that wraps ALL the panels, and in the event handler, the e.target is (possibly inside) the panel.我将事件侦听器添加到包含所有面板的 OUTER div 中,并且在事件处理程序中,e.target 是(可能在内部)面板。 So to get the panel itself, I use.closest to make sure we are acting on the wrapper因此,为了获取面板本身,我使用 .closest 来确保我们正在对包装器进行操作

 const wrapper = document.querySelector(".projects"); /* what moves the divs */ const onDrag = ({ movementX, movementY }) => { const wrapperPanel = wrapper.querySelector(".panel.active") let getStyle = window.getComputedStyle(wrapperPanel); let leftVal = parseInt(getStyle.left); let topVal = parseInt(getStyle.top); wrapperPanel.style.left = `${leftVal + movementX}px`; wrapperPanel.style.top = `${topVal + movementY}px`; } const mouse = (e) => { const tgt = e.target.closest(".panel"); if (tgt) tgt.classList.toggle("active",e.type=="mousedown"); }; wrapper.addEventListener("mousedown", mouse) wrapper.addEventListener("mouseup", mouse) wrapper.addEventListener("mousemove", onDrag);
 .projects { display: flex; width: 100%; height: 125vh; background-image: url(images/laptop.png); background-position: 100%; background-position-y: center; background-position-x: center; background-size: 95%; background-repeat: no-repeat; } .gamedev-panel { position: absolute; top: 3rem; left: 16rem; width: 40rem; height: 30rem; background-color: #403d39; } .gamedev-titlebar { height: 3rem; background: #EB5E28; display: flex; align-items: center; justify-content: right; } .btn-1 { background: turquoise; } .btn-2 { background: yellow; } .btn-3 { background: red; } .game-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-right: 1rem; } .gamedev-heading { background: none; position: absolute; /* width: 369.43px; height: 40.32px; left: 408.26px; top: 2592.77px; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #CCC5B9; pointer-events: none; } .gamedev-gif { position: absolute; bottom: 1rem; right: 1rem; pointer-events: none; } .webdev-panel { position: absolute; top: 1rem; right: 16rem; width: 25rem; height: 30rem; background-color: #fffcf2; display: inline-flex; justify-content: flex-end; overflow: hidden; } .webdev-titlebar { /* position: absolute; */ height: 30rem; width: 3rem; background: #EB5E28; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; pointer-events: none; } .web-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-top: 1rem; /* margin-right: 1rem; */ pointer-events: none; } .webdev-heading { background: none; /* position: absolute; right: 5rem; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #252422; pointer-events: none; } .webdev-content { margin-right: 1rem; pointer-events: none; } .webdev-img { width: 80%; height: 80%; position: absolute; right: 4rem; top: 5rem; pointer-events: none;
 <div class="projects"> <div class="gamedev-panel panel"> <div class="gamedev-titlebar"> <div class="btn-1 game-btn"></div> <div class="btn-2 game-btn"></div> <div class="btn-3 game-btn"></div> </div> <h2 class="gamedev-heading">I DEVELOP GAMES</h2> <img src="images/game.gif" alt="" class="gamedev-gif"> </div> <div class="webdev-panel panel"> <div class="webdev-content"> <h2 class="webdev-heading">I MAKE WEBSITES</h2> <img src="images/web.png" alt="" class="webdev-img"> </div> <div class="webdev-titlebar"> <div class="btn-1 web-btn"></div> <div class="btn-2 web-btn"></div> <div class="btn-3 web-btn"></div> </div> </div> <div class="others-panel"></div> </div>

The upper bound of wrapper.length - 1 excludes the last .panel . wrapper.length - 1的上限不包括最后一个.panel

Additionally, there are various issues with variable bindings:此外,变量绑定存在各种问题:

  • wrapper in onDrag is a NodeList , not an HTMLElement. onDrag中的wrapperNodeList ,而不是 HTMLElement。 onDrag must operate on a specific element of wrapper , rather than the whole collection. onDrag必须对wrapper的特定元素进行操作,而不是对整个集合进行操作。
  • since i isn't block-local and is updated in the loop, it will be the last value i takes (one past the loop end condition);因为i不是块本地的并且在循环中更新,所以它将是i采用的最后一个值(超过循环结束条件); wrapper[i] in the mouse event handlers will only ever refer to one thing.鼠标事件处理程序中的wrapper[i]只会引用一件事。 Declaring i with let will make it block-local, and wrapper[i] within the event handlers will then refer to the correct element.let声明i将使其成为块本地,并且事件处理程序中的wrapper[i]将引用正确的元素。

Note that both the above binding issues are already covered by other questions on SO.请注意,关于 SO 的其他问题已经涵盖了上述两个约束性问题。

your code needs some changes.您的代码需要一些更改。

  1. don't use variable i in a function inside a loop.不要在循环内的函数中使用变量i variables are all refrence.变量都是参考。
  2. don't use arrow function to access this pointer of current element不要使用箭头函数来访问当前元素的this指针
  3. change your wrapper[i] in onDrag to this like aboveonDrag中的wrapper[i]更改为this
  4. add user-select:none inside the .panel to be not selectable in css.panel中添加user-select:none以在 css 中不可选择
  5. add mouse out event to current element for the time the mouse jumped out of the screen and the mouseup doesn't fire在鼠标跳出屏幕且mouseup不触发时,将 mouse out 事件添加到当前元素

 var wrapper = document.querySelectorAll(".panel"); for (i = 0; i < wrapper.length; i++) { wrapper[i].addEventListener("mousedown",function () { this.classList.add("active"); this.addEventListener("mousemove", onDrag); }); wrapper[i].addEventListener("mouseup",function () { this.classList.remove("active"); this.removeEventListener("mousemove", onDrag); }); wrapper[i].addEventListener("mouseout",function () { this.removeEventListener("mousemove", onDrag); }); } function onDrag({ movementX, movementY }) { let getStyle = window.getComputedStyle(this); let leftVal = parseInt(getStyle.left); let topVal = parseInt(getStyle.top); this.style.left = `${leftVal + movementX}px`; this.style.top = `${topVal + movementY}px`; }
 .panel { user-select: none; } .projects { display: flex; width: 100%; height: 125vh; background-image: url(images/laptop.png); background-position: 100%; background-position-y: center; background-position-x: center; background-size: 95%; background-repeat: no-repeat; } .gamedev-panel { position: absolute; top: 3rem; left: 16rem; width: 40rem; height: 30rem; background-color: #403d39; } .gamedev-titlebar { height: 3rem; background: #EB5E28; display: flex; align-items: center; justify-content: right; } .btn-1 { background: turquoise; } .btn-2 { background: yellow; } .btn-3 { background: red; } .game-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-right: 1rem; } .gamedev-heading { background: none; position: absolute; /* width: 369.43px; height: 40.32px; left: 408.26px; top: 2592.77px; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #CCC5B9; pointer-events: none; } .gamedev-gif { position: absolute; bottom: 1rem; right: 1rem; pointer-events: none; } .webdev-panel { position: absolute; top: 1rem; right: 16rem; width: 25rem; height: 30rem; background-color: #fffcf2; display: inline-flex; justify-content: flex-end; overflow: hidden; } .webdev-titlebar { /* position: absolute; */ height: 30rem; width: 3rem; background: #EB5E28; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; pointer-events: none; } .web-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-top: 1rem; /* margin-right: 1rem; */ pointer-events: none; } .webdev-heading { background: none; /* position: absolute; right: 5rem; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #252422; pointer-events: none; } .webdev-content { margin-right: 1rem; pointer-events: none; } .webdev-img { width: 80%; height: 80%; position: absolute; right: 4rem; top: 5rem; pointer-events: none; }
 <div class="projects"> <div class="gamedev-panel panel"> <div class="gamedev-titlebar"> <div class="btn-1 game-btn"></div> <div class="btn-2 game-btn"></div> <div class="btn-3 game-btn"></div> </div> <h2 class="gamedev-heading">I DEVELOP GAMES</h2> <img src="images/game.gif" alt="" class="gamedev-gif"> </div> <div class="webdev-panel panel"> <div class="webdev-content"> <h2 class="webdev-heading">I MAKE WEBSITES</h2> <img src="images/web.png" alt="" class="webdev-img"> </div> <div class="webdev-titlebar"> <div class="btn-1 web-btn"></div> <div class="btn-2 web-btn"></div> <div class="btn-3 web-btn"></div> </div> </div> <div class="others-panel"></div> </div>

You're adding several mouseup event listeners to your document ,you're iterating up to 2 indexes below the final length of your element array, and you're never declaring your i variable.您正在向document中添加几个mouseup事件侦听器,您正在迭代元素数组的最终长度以下最多 2 个索引,并且您永远不会声明您的i变量。

In your event mousemove listener, you're using the wrapper variable that you haven't redeclared from your previous code.在您的事件 mousemove 侦听器中,您正在使用尚未从之前的代码中重新声明的wrapper变量。 You can use the target property from the event object to get the element calling your listener.您可以使用event对象中的target属性来获取调用您的侦听器的元素。

 var wrapper = document.querySelectorAll(".panel"); for (let i = 0; i < wrapper.length; i++) { /* multiple event listeners for mouse up and down */ wrapper[i].addEventListener("mousedown", () => { wrapper[i].classList.add("active"); wrapper[i].addEventListener("mousemove", onDrag); console.log("check mouse down"); /* checking mouse down */ }); function mouseMove() { wrapper[i].classList.remove("active"); wrapper[i].removeEventListener("mousemove", mouseMove); wrapper[i].removeEventListener("mousemove", onDrag); console.log("check mouse up"); /* checking mouse down */ }; wrapper[i].addEventListener("mouseup", mouseMove); } /* what moves the divs */ function onDrag(event) { let getStyle = window.getComputedStyle(event.target); let leftVal = parseInt(getStyle.left); let topVal = parseInt(getStyle.top); event.target.style.left = `${leftVal + event.movementX}px`; event.target.style.top = `${topVal + event.movementY}px`; }
 .projects { display: flex; width: 100%; height: 125vh; background-image: url(images/laptop.png); background-position: 100%; background-position-y: center; background-position-x: center; background-size: 95%; background-repeat: no-repeat; } .gamedev-panel { position: absolute; top: 3rem; left: 16rem; width: 40rem; height: 30rem; background-color: #403d39; } .gamedev-titlebar { height: 3rem; background: #EB5E28; display: flex; align-items: center; justify-content: right; } .btn-1 { background: turquoise; } .btn-2 { background: yellow; } .btn-3 { background: red; } .game-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-right: 1rem; } .gamedev-heading { background: none; position: absolute; /* width: 369.43px; height: 40.32px; left: 408.26px; top: 2592.77px; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #CCC5B9; pointer-events: none; } .gamedev-gif { position: absolute; bottom: 1rem; right: 1rem; pointer-events: none; } .webdev-panel { position: absolute; top: 1rem; right: 16rem; width: 25rem; height: 30rem; background-color: #fffcf2; display: inline-flex; justify-content: flex-end; overflow: hidden; } .webdev-titlebar { /* position: absolute; */ height: 30rem; width: 3rem; background: #EB5E28; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; pointer-events: none; } .web-btn { width: 1.5rem; height: 1.5rem; border-radius: 50%; margin-top: 1rem; /* margin-right: 1rem; */ pointer-events: none; } .webdev-heading { background: none; /* position: absolute; right: 5rem; */ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; font-size: 36px; line-height: 45px; letter-spacing: 0.1em; margin-left: 1rem; color: #252422; pointer-events: none; } .webdev-content { margin-right: 1rem; pointer-events: none; } .webdev-img { width: 80%; height: 80%; position: absolute; right: 4rem; top: 5rem; pointer-events: none;
 <div class="projects"> <div class="gamedev-panel panel"> <div class="gamedev-titlebar"> <div class="btn-1 game-btn"></div> <div class="btn-2 game-btn"></div> <div class="btn-3 game-btn"></div> </div> <h2 class="gamedev-heading">I DEVELOP GAMES</h2> <img src="images/game.gif" alt="" class="gamedev-gif"> </div> <div class="webdev-panel panel"> <div class="webdev-content"> <h2 class="webdev-heading">I MAKE WEBSITES</h2> <img src="images/web.png" alt="" class="webdev-img"> </div> <div class="webdev-titlebar"> <div class="btn-1 web-btn"></div> <div class="btn-2 web-btn"></div> <div class="btn-3 web-btn"></div> </div> </div> <div class="others-panel"></div> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM