使用原生JS寫出一個九宮格,實現九個格子何以拖拽換位的效果,供大家參考,具體內容如下
效果演示
具體思路分析和代碼:
圖解1:
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
<!DOCTYPE html> < html lang = "en" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < title >Document</ title > <!-- 思路梳理: 1,樣式設置:在樣式里最好使用定位來布局,不然以后拖拽代碼會麻煩點兒。 (這里沒有設置父容器的具體位置,如果設置了父容器的具體位置,則在移動 時top和left的值需要根據情況計算位置) 2,父容器盒子里的內容最好使用js代碼來生成,方便使用和添加樣式 2-1:(循環生成子元素) 我們子元素使用的定位布局,不難發現:每行的top值一樣,每列的left值一樣,因此循環生 成子元素我們可以使用3*3的循環嵌套來寫,這樣就可以講每行的樣式設置了。 2-2:(給循環生成的標簽添加隨機顏色和文字) 隨機顏色我是用的時rgb()來實現的,文字可以使用ASCII碼來生成,也可以使用字符串拼接 來生成,我這里使用ASCII碼生成。 PS:這樣我們的基本樣式就設置完畢了,接下來就是設置拖拽的事件 3,給每一個元素添加事件,這里我們需要三個事件: onmousedown - onmousemove - onmouseup 3-1:(首先是按下事件 onmousedown) 當我們在對應子元素按下時,我們要獲取鼠標到按下目標邊框線內的距離,并且克隆這個元素, 將這個元素扔到父容器里面充當占位,(這里注意,克隆的這個節點在HTML結構里是放到最后 的,如果不處理后面會出BUG!!!)。 3-2:(然后處理移動事件 onmousemove) 在按下子元素塊兒并且移動時,我們要給目標設置他的top和left值,來實現跟隨移動,所以 我們需要獲取鼠標到可視窗口的距離,目標的top和left值 = 鼠標到可視窗口的距離 - 鼠標 到目標邊緣的距離(這里無邊框,如果有需要額外減去邊框寬度)。 PS: 這里存在一個BUG!!!!在拖拽時,存在一個默認事件--選中文字,當你松開之后,目 標還會跟著走,就算你關閉了onmousemove這個事件。所以這里需要阻止一下默認事件。 3-3:(最后處理抬起事件 onmouseup)這里也是最重要的一步!!!! 核心思想: 當鼠標抬起時,我們要計算當前移動目標的中心點和每一個子元素中心點的距離, 哪一個離得最近,和哪個交換位置(注意,這里存在一個BUG,這里的BUG就是 3-1 里提到的BUG,需要提前處理)。 具體過程: 3-3-1: 首先我們要進行循環,計算拖拽目標的中心點與每一個子元素的中心點的距離,具體 參照 圖解1 。 (拖拽目標距離可視窗口的左邊距 - 子元素距離可視窗口的左邊 距)平方 + (拖拽目標距離可視窗口的上邊距 - 子元素距離可視窗口的上邊距) 平方。最后在開方,得到中心點的距離(注意3-1的BUG要處理掉,把,要把移動的 標簽放到結構的最后,然后循環的時候將他排除掉,不然每次距離最近的都是它本身)。 3-3-2: 我們循環會得到我們想要的每一個距離,然后將這些距離放到一個數組里,并且再定 義一個數組備份一下,方便對照具體是哪個標簽。 將其中一個數組進行排序,然后再備份數組中查一下最小的值在備份數組中的索引下 標,這個索引下標也就是對應的子元素了。 3-3-3: 然后將距離最近的子元素的 left和top值給 目標元素 然后將克隆的標簽的 left和top值給 距離最近的子元素 最后在將克隆的標簽移除掉 這里還是會有一個BUG!!!如果不在標簽上按 直接抬起鼠標的話,會報錯,這是因 為直接執行了onmouseup事件,所以需要移除掉onmouseup事件 --> < style > *{margin: 0;padding: 0;} .father{position: relative;} .father div{position: absolute;width: 100px;height: 100px;border-radius: 10px;text-align: center;line-height: 100px;font-size: 30px;cursor: pointer;} </ style > </ head > < body > < div class = "father" ></ div > < script > // 3*3 循環生成子元素div,并給他們設置定位值 // 設定固定的margin值 var mT = 15; var mL = 15; var asc = 65;//ASCII碼值 var oFather = document.querySelector('.father'); for(var i = 0; i < 3 ; i++){ for(var j = 0 ; j < 3; j++){ var oDiv = document .createElement('div');//創建子元素 oFather.appendChild(oDiv); oDiv.style.left = j * (oDiv.offsetWidth + mL) +'px'; oDiv.style.top = i * (oDiv.offsetHeight + mT) +'px'; // 隨機顏色設置 oDiv.style.background = 'rgb(' +parseInt(Math.random()*256) + "," +parseInt(Math.random()*256) + ","+parseInt(Math.random()*256)+')'; // 加上字母 oDiv.innerText = String .fromCharCode(asc++); } } // 為了方便理解,將事件寫到了外面,這里可以生成標簽循環內部 /* var oItem = document .querySelectorAll('.father>div'); 這種方式獲取的是靜態集合,只會獲取到初次頁面加載的內容,用這種辦法獲取子元素會出BUG */ var oItem = oFather.children; for(var k = 0 ;k< oItem.length ; k++){ oItem[k] .onmousedown = function (e){ var evt = e || event; // 獲取鼠標到目標邊框內的距離 var x = e .offsetX; var y = e .offsetY; var tagNode = this ; // 克隆目標標簽 var cloneNode = tagNode .cloneNode(); cloneNode.style.border = '1px dashed #fff' ; oFather.appendChild(cloneNode); tagNode.style.zIndex = 1 ; // 在思路里提到過,這里存在一個BUG需要將克隆的和被拖拽換位置 oFather.replaceChild(cloneNode, tagNode); oFather.appendChild(tagNode); document.onmousemove = function (e){ var evt = e || event ; var l = evt .clientX - x; var t = evt .clientY - y; tagNode.style.left = l + 'px'; tagNode.style.top = t + 'px'; // 阻止默認事件,防止bug return false; } document.onmouseup = function (){ // 抬起鼠標后,要判斷離那個最近,然后交換 var oldArr = []; var newArr = []; for(var l = 0 ; l<oItem.length - 1;l++){ var disX = tagNode .offsetLeft - oItem[l].offsetLeft; var disY = tagNode .offsetTop - oItem[l].offsetTop; // 勾股定理 var dis = Math .sqrt( Math.pow(disX,2) + Math.pow(disY,2) ); oldArr.push(dis); newArr.push(dis); } // 將oldArr從小到大排序 oldArr.sort(function(a,b){return a-b}); var minIndex = newArr .indexOf(oldArr[0]); console.log('oldArr' , oldArr, 'newArr' ,newArr); // 將距離最近的元素的定位給移動的目標 tagNode.style.top = oItem [minIndex].style.top; tagNode.style.left = oItem [minIndex].style.left; // 把克隆的定位給距離最近的 oItem[minIndex] .style.top = cloneNode .style.top; oItem[minIndex] .style.left = cloneNode .style.left; //把克隆節點移除 oFather.removeChild(cloneNode); document.onmousemove = null ; document.onmouseup = null ; } return false; } } </script> </ body > </ html > |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/m0_46387873/article/details/106955195