使用原生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