16宫格拖拽

实现一个如图所示的16宫格页面,其中各个数字盒子之间是能相互拖拽,并交换位置的。而横纵各自的标题栏ABC与XYZ实现的功能则是,ABC(XYZ)之间两两互换位置,从而引起两列(行)一起调换位置。

需求

实现一个如图所示的16宫格页面,其中各个数字盒子之间是能相互拖拽,并交换位置的。而横纵各自的标题栏ABC与XYZ实现的功能则是,ABC(XYZ)之间两两互换位置,从而引起两列(行)一起调换位置。

示意图

外观处理

  • 设置外层容器与内部方块宽度,并向左浮动,从而构成16宫格;
  • 每个盒子的位置以坐标(x,y)来表示,其中0<x,y<4;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#container {
position: relative;
width: 400px;
height: 400px;
background: #eee;
}
.box {
float: left;
width: 70px;
height: 70px;
margin: 5px;
font-weight: bold;
line-height: 70px;
text-align: center;
border: 10px solid red;
border-radius: 10px;
}
  • 由于拖拽使用的是绝对定位,因此首先获取当前各个盒子的偏移量,然后将盒子的position属性设为absolute,使用对应的偏移量设置top与left。

1
2
3
4
5
6
7
8
9
10
function absoluteThem(e) {
$($(".box").toArray().reverse()).each(function(index, el) {
$(this).css({
"left": $(this).position().left,
"top": $(this).position().top,
"float": "none",
"position": "absolute"
});
});
}

拖拽处理

注意盒子越界检查以及标题栏的字母只能横向或纵向移动,并保存被拖拽盒子的坐标


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
function clickNum(e) {//点击数字
var targetEle = e.target,
targetEleJQ = $(targetEle),
oriX = e.clientX - targetEle.offsetLeft, //光标按下时相对本身的坐标
oriY = e.clientY - targetEle.offsetTop;
if (targetEleJQ.hasClass("undraggable")) {
return;
}
$(document).bind("mousemove", moveIt);
$(document).bind("mouseup", mouseUp);

function moveIt(e2) {//移动
var newX = e2.clientX - oriX,
newY = e2.clientY - oriY,
maxX = 400 - targetEle.offsetWidth - 10,
maxY = 400 - targetEle.offsetHeight - 10;
if (newX < 100) {
newX = 100;
} else if (newX > maxX) {
newX = maxX;
}
if (newY < 100) {
newY = 100;
} else if (newY > maxY) {
newY = maxY;
}
if(targetEleJQ.hasClass("num")){//如果是数字
targetEle.style.left = newX + "px";
targetEle.style.top = newY + "px";
}
else if(targetEleJQ.hasClass("group1")){//如果是ABC栏
targetEle.style.left = newX + "px";
}
else if(targetEleJQ.hasClass("group2")){//如果是XYZ栏
targetEle.style.top = newY + "px";
}
}

放下盒子

释放鼠标处的盒子坐标:将鼠标当前位置clientX与clientY分别对100求余,并向下取整,即可得到。


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
function mouseUp(e3) {
var boxLocX = Math.floor(e3.clientY/100),//放下光标时,所在的方格坐标
boxLocY = Math.floor(e3.clientX/100),
oriBoxLocX = parseInt(targetEle.id.substr(4,1)),//原来的方格坐标
oriBoxLocY = parseInt(targetEle.id.substr(6,1)),
boxNow = "box-" + boxLocX + "-" + boxLocY,//放下处的盒子id
boxOri = "box-" + oriBoxLocX + "-" + oriBoxLocY;

if(targetEleJQ.hasClass("group1")) {
if(!$("#" + boxNow).hasClass("letter") || $("#" + boxNow).hasClass("group2")){//点击的是字母而释放的是非字母
resetLoc(boxOri);
return;
}
changeLoc(boxNow, boxOri);
for(var i = 1; i < 4; i++){
boxLocX ++;
oriBoxLocX ++;
boxNow = "box-" + boxLocX + "-" + boxLocY;//放下处的盒子id
boxOri = "box-" + oriBoxLocX + "-" + oriBoxLocY;
changeLoc(boxNow, boxOri);
}
}
else if (targetEleJQ.hasClass("group2")) {
if(!$("#" + boxNow).hasClass("letter") || $("#" + boxNow).hasClass("group1")){//点击的是字母而释放的是非字母
resetLoc(boxOri);
return;
}
changeLoc(boxNow, boxOri);
for(var j = 1; j < 4; j++){
boxLocY ++;
oriBoxLocY ++;
boxNow = "box-" + boxLocX + "-" + boxLocY;//放下处的盒子id
boxOri = "box-" + oriBoxLocX + "-" + oriBoxLocY;
changeLoc(boxNow, boxOri);
}
}
else{
if(!$("#" + boxNow).hasClass("num")){
resetLoc(boxOri);
return;
}
changeLoc(boxNow, boxOri);
}
$(document).unbind("mousemove", moveIt);
$(document).unbind("mouseup", mouseUp);

完整代码

文章目录
  1. 1. 需求
  2. 2. 外观处理
  3. 3. 拖拽处理
  4. 4. 放下盒子
,