1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 <title>Document</title>
16 <style>
17 /* Unable to preventDefault inside passive event listener due to target being treated as passive */
18 * { touch-action: none; }
19 body,ul,li{margin:0;padding:0;}
20 ul{list-style: none;}
21 body{font:13px/1.5 Tahoma;width:100%;height:100%}
22 html{width:100%;height:100%}
23 #box{position:relative;width:100%;height:100%;}
24 #box li{float:left;width:100%;height:50px;overflow:hidden;background: #ccc;border:2px solid #999999;}
25 #box li.hig{width:100%;height:50px;overflow:hidden;border:2px dashed blue;}
26 </style>
27 </head>
28 <body>
29 <ul id="box"></ul>
30 <script>
31 let zIndex = 1
32 window.onload = function() {
33 let oBox = document.getElementById("box")
34 let aLi = oBox.getElementsByTagName("li")
35 let aPos = []
36 let aData = []
37 for (let i = 0; i < 6; i++){
38 aData.push(i+1)
39 }
40 //插入结构
41 let oFragment = document.createDocumentFragment()
42 for (let i = 0; i < aData.length; i++) {
43 let oLi = document.createElement("li")
44 oLi.innerHTML = i+1
45 oFragment.appendChild(oLi)
46 }
47 oBox.appendChild(oFragment)
48 //布局转换
49 for (let i = 0; i < aLi.length; i++) {
50 aLi[i].index = i
51 aLi[i].style.top = Math.ceil(aLi[i].offsetTop) + "px"
52 aLi[i].style.left = Math.ceil(aLi[i].offsetLeft) + "px"
53 aLi[i].style.margin = "0 5px 5px 0"
54 aPos.push({
55 "left": aLi[i].offsetLeft,
56 "top": aLi[i].offsetTop
57 })
58 }
59 for (let i = 0; i < aLi.length; i++) {
60 aLi[i].style.position = "absolute"
61 drag(aLi[i])
62 }
63
64 //拖拽函数
65 function drag(obj, handle) {
66 let newHandle = handle || obj
67 newHandle.style.cursor = "move"
68 newHandle.onmousedown = newHandle.ontouchstart = function(evt) {
69 let event = evt || window.event
70 let disX,disY
71 if(event.type=='touchstart'){
72 let touch = event.touches[0]
73 disX = Number(touch.pageX) - this.offsetLeft
74 disY = Number(touch.pageY) - this.offsetTop
75 }else{
76 disX = event.clientX - this.offsetLeft
77 disY = event.clientY - this.offsetTop
78 }
79 let oNear = null
80 obj.style.zIndex = zIndex++
81 document.onmousemove = document.ontouchmove = function(evt) {
82 let event = evt || window.event
83 let iL,iT
84 if(event.type=='touchmove'){
85 let touch = event.touches[0]
86 iL = Number(touch.pageX) - disX
87 iT = Number(touch.pageY) - disY
88 }else{
89 iL = event.clientX - disX
90 iT = event.clientY - disY
91 }
92
93 let maxL = obj.parentNode.clientWidth - obj.offsetWidth
94 let maxT = obj.parentNode.clientHeight - obj.offsetHeight
95
96 iL < 0 && (iL = 0)
97 iT < 0 && (iT = 0)
98 iL > maxL && (iL = maxL)
99 iT > maxT && (iT = maxT)
100 obj.style.left = Math.ceil(iL) + "px"
101 obj.style.top = Math.ceil(iT) + "px"
102
103 for (i = 0; i < aLi.length; i++){
104 aLi[i].className = ""
105 }
106
107 oNear = findNearest(obj)
108
109 oNear && (oNear.className = "hig")
110
111 return false
112 }
113 document.onmouseup = document.ontouchend = function() {
114 document.onmousemove = document.ontouchmove = null
115 document.onmouseup = document.ontouchend = null
116 if (oNear) {
117 let tIndex = obj.index
118 obj.index = oNear.index
119 oNear.index = tIndex
120 startMove(obj, aPos[obj.index])
121 startMove(oNear, aPos[oNear.index], function() {})
122 oNear.className = ""
123 let data = [Number(obj.index)+1,Number(oNear.index)+1]
124 let minNumber = Math.min.apply(Math,data)
125 let maxNumber = Math.max.apply(Math,data)
126 changeArraryElement(aData,minNumber,maxNumber)
127 console.log('data之后',aData)
128 } else {
129 startMove(obj, aPos[obj.index])
130 }
131 newHandle.releaseCapture && newHandle.releaseCapture()
132 // console.log('aData',aData)
133 // console.log('aPos',aPos)
134 }
135 this.setCapture && this.setCapture()
136 return false
137 }
138 }
139
140 //找出相遇点中最近的元素
141 function findNearest(obj) {
142 let filterLi = []
143 let aDistance = []
144 for (i = 0; i < aLi.length; i++) aLi[i] != obj && (isButt(obj, aLi[i]) && (aDistance.push(getDistance(obj, aLi[i])), filterLi.push(aLi[i])))
145 let minNum = Number.MAX_VALUE
146 let minLi = null
147 for (i = 0; i < aDistance.length; i++) aDistance[i] < minNum && (minNum = aDistance[i], minLi = filterLi[i])
148 return minLi
149 }
150 }
151
152 //求两点之间的距离
153 function getDistance(obj1, obj2) {
154 let a = (obj1.offsetLeft + obj1.offsetWidth / 2) - (obj2.offsetLeft + obj2.offsetWidth / 2)
155 let b = (obj1.offsetTop + obj1.offsetHeight / 2) - (obj2.offsetTop + obj2.offsetHeight / 2)
156 return Math.sqrt(a * a + b * b)
157 }
158
159 //碰撞检测
160 function isButt(obj1, obj2) {
161 let l1 = obj1.offsetLeft
162 let t1 = obj1.offsetTop
163 let r1 = obj1.offsetLeft + obj1.offsetWidth
164 let b1 = obj1.offsetTop + obj1.offsetHeight
165
166 let l2 = obj2.offsetLeft
167 let t2 = obj2.offsetTop
168 let r2 = obj2.offsetLeft + obj2.offsetWidth
169 let b2 = obj2.offsetTop + obj2.offsetHeight
170
171 return !(r1 < l2 || b1 < t2 || r2 < l1 || b2 < t1)
172 }
173
174 //获取最终样式
175 function getStyle(obj, attr) {
176 return parseFloat(obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, null)[attr])
177 }
178
179 //运动框架
180 function startMove(obj, pos, onEnd) {
181 clearInterval(obj.timer)
182 obj.timer = setInterval(function() {
183 doMove(obj, pos, onEnd)
184 }, 30)
185 }
186
187 function doMove(obj, pos, onEnd) {
188 let iCurL = getStyle(obj, "left")
189 let iCurT = getStyle(obj, "top")
190 let iSpeedL = (pos.left - iCurL) / 5
191 let iSpeedT = (pos.top - iCurT) / 5
192 iSpeedL = iSpeedL > 0 ? Math.ceil(iSpeedL) : Math.floor(iSpeedL)
193 iSpeedT = iSpeedT > 0 ? Math.ceil(iSpeedT) : Math.floor(iSpeedT)
194 if (pos.left == iCurL && pos.top == iCurT) {
195 clearInterval(obj.timer)
196 onEnd && onEnd()
197 } else {
198 obj.style.left = Math.ceil(iCurL + iSpeedL) + "px"
199 obj.style.top = Math.ceil(iCurT + iSpeedT) + "px"
200 }
201 }
202
203 //交换第几个元素的数组操作,注意:x>y
204 function changeArraryElement(arr1,x1,y1){
205 let arr = arr1
206 let x = x1, y = y1
207 arr.splice(x - 1, 1, ...arr.splice(y - 1, 1, arr[x - 1]))
208 return arr
209 }
210 </script>
211 </body>
212 </html>