前端页面元素拖动

最近工作不是很忙,所以借这个时间整理一下之前遇到的问题,记录一下相关的解决方案。

首先整理一下页面元素拖动实现的思路:

  1. 由于页面上可拖动的元素数量是不固定的,所以不应该把事件监听函数绑定到每个元素上,可以使用事件代理,将事件监听函数绑定到父级元素上。
  2. 移动位置的计算有2种思路,第一种是在mousedown事件触发时,记录鼠标事件的位置和元素的位置,然后mousemove事件每次触发,用当前的鼠标事件位置减mousedown事件的鼠标位置,移动的距离,再加上mousedown事件触发时记录的元素左边和上边的距离,即可计算出新的位置,简单地说就是鼠标每次移动后的位置与鼠标初始位置比较,得出移动的距离。第二种就是每次mousemove事件触发,都与上一次的位置进行比较;这种方法算起来比较麻烦,所以我采用第一种计算方法。
  3. 具体计算方法是这样的,在mousedown触发后,记录鼠标的位置,即e.clientX,e.clientY,以及元素距离左边和上边的距离,e.target.offsetLeft和e.target.offsetTop,因为我将父级元素的position设为relative,所以这两个值是元素边框外侧到父元素边框内侧的距离,在mousemove触发时,记录鼠标的新位置,即e.clientX,e.clientY,然后用 鼠标新位置 - 鼠标初始位置 + 元素初始左、上距离 算出新的位置,然后将元素position设为absolute,计算出的值即为left和top的值。
  4. 有2个需要注意的地方,第一,mousemove事件与mousedown,mouseup2个并不是连续的事件,当鼠标移动至少1个像素时,mousemove事件就会触发,与鼠标是否按下无关,所以需要在事件处理函数中校验拖动的元素是否为同一个对象;第二,还是因为mousemove事件与mousedown,mouseup2个并不是连续的事件,必须要保证mousemove事件是在mousedown事件后触发的,即鼠标按下,然后移动,不能是,鼠标按下,鼠标松开,然后移动。对于这两个问题,解决思路是一致的,都是在父级作用域中定义变量来控制,对于第一个问题,在mousedown事件触发后,将目标元素对象赋值给定义好的变量,然后在mousemove事件中校验事件对象元素是否为同一个元素,对于第二个问题,在父级作用域中定义一个flag,当mousedown触发,设为true,mouseup触发,设为false,在mousemove触发,校验是否为true就行了。

示例代码如下:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3   <head>
 4     <meta charset="UTF-8" />
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 6     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 7     <title>Document</title>
 8     <style>
 9       .rect {
10         width: 100px;
11         height: 100px;
12         background-color: #eee;
13         margin: 5px;
14       }
15       .box {
16         position: relative;
17       }
18     </style>
19   </head>
20   <body>
21     <div class="box">
22       <p class="rect"></p>
23       <p class="rect"></p>
24       <p class="rect"></p>
25       <p class="rect"></p>
26       <p class="rect"></p>
27       <p class="rect"></p>
28       <p class="rect"></p>
29       <p class="rect"></p>
30       <p class="rect"></p>
31       <p class="rect"></p>
32       <p class="rect"></p>
33       <p class="rect"></p>
34       <p class="rect"></p>
35     </div>
36 
37     <script>
38       let position = {
39         x: 0,
40         y: 0,
41         left: 0,
42         top: 0,
43       }
44       let target = null
45       isDown = false
46       let box = document.querySelector(".box")
47       box.addEventListener("mousedown", function (e) {
48         if (!e.target.className.includes("rect")) return
49         target = e.target
50         position.x = e.clientX
51         position.y = e.clientY
52         position.left = e.target.offsetLeft
53         position.top = e.target.offsetTop
54         isDown = true
55       })
56 
57       box.addEventListener("mousemove", function (e) {
58         if (!e.target.className.includes("rect")) return
59         if (!isDown) return
60         target.style.position = "absolute"
61         let mx = e.clientX
62         let my = e.clientY
63         let myLeft = mx - position.x + position.left
64         let myTop = my - position.y + position.top
65 
66         console.log({ myLeft, myTop })
67         target.style.left = myLeft + "px"
68         target.style.top = myTop + "px"
69       })
70       box.addEventListener("mouseup", function (e) {
71         if (isDown) isDown = false
72       })
73     </script>
74   </body>
75 </html>

 

posted @ 2021-06-10 13:51  KlllB  阅读(558)  评论(0编辑  收藏  举报