JS 实现拖拽之 - 九宫格拖拽
2019-07-02 本文已影响52人
CondorHero
九宫格.gif
实现思路和需要掌握的技术:
- 鼠标拖拽模型实现
- li 盒子进行绝对定位
- 批量监听和批量操作 li 盒子
- 判断条件为移动盒子的 top 和 left 在另一个盒子之内。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>九宫格</title>
<style>
*{
margin:0;
padding:0;
}
ul{
position: relative;
list-style:none;
width: 1062px;
height: 1500px;
border: 1px solid #333;
margin:0 auto;
}
ul li{
position: absolute;
width: 354px;
height: 500px;
background:url("animate.jpg") no-repeat;
cursor: pointer;
}
/*拖拽的时候让拖拽的图片置于其他图片上面*/
.active{
z-index:1;
}
</style>
</head>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
</html>
<script>
//得到元素
var uls = document.querySelector("ul");
var lis = uls.querySelectorAll("li");
// 批量添加监听
for(var i = 0;i < lis.length;i++){
// 批量放置li盒子的位置和里面的图片
lis[i].style.left = (i % 3) * 354 + "px";
lis[i].style.top = parseInt(i / 3) * 500 + "px";
lis[i].style.backgroundPosition = -(i % 3) * 354 + "px " + -parseInt(i / 3) * 500 + "px";
// 闭包的影响属性法备份 i
lis[i].index = i;
// 鼠标按下
lis[i].onmousedown = function(event){
// 兼容IE
event = event || window.event;
// 鼠标到每个li盒子内层最顶端和最左端的位置
var lisx = event.clientX - this.offsetLeft;
var lisy = event.clientY - this.offsetTop;
// 备份this
var self = this;
document.onmousemove = function(event){
// console.log(self);//如果是this这时this指代的是document
// 兼容IE
event = event || window.event;
// li盒子到它的offsetparent的距离,就是离li最近定位的盒子
lisL = event.clientX - lisx;
lisT = event.clientY - lisy;
self.className = "active";
// 改变移动盒子的定位,做到鼠标跟随
self.style.left = lisL + "px";
self.style.top = lisT + "px";
}
// 鼠标抬起
document.onmouseup = function(event){
// 兼容IE
event = event || window.event;
// 清除鼠标移动时间
document.onmousemove = null;
// 移出每个添加类名的元素
self.className = "";
// 批量遍历每个盒子是否满足交换条件
for(var j = 0;j < lis.length;j++){
if(lis[j].offsetLeft + lis[j].offsetWidth > self.offsetLeft && lis[j].offsetTop + lis[j].offsetHeight > self.offsetTop && lis[j].offsetLeft < self.offsetLeft && lis[j].offsetTop < self.offsetTop){
// console.log(self.index)
// 满足条件的时候交换两个盒子元素的属性值 index
var temp = lis[j].index;
lis[j].index = self.index;
self.index = temp;
// 交换位置
lis[j].style.left = (lis[j].index % 3) * 354 + "px";
lis[j].style.top = parseInt(lis[j].index / 3) * 500 + "px";
// 如果找到就退出循环。不在进行查找
break;
}
}
// 这时在改变移动盒子的位置
// 本来是放在for循环里面的,但是拿出来可以防止盒子不在监听位置的时候
// 也就是index未改变的时候,会回到自己的原位置
self.style.left = (self.index % 3) * 354 + "px";
self.style.top = parseInt(self.index / 3) * 500 + "px";
}
// 防止浏览器的默认事件
// 例如拖拽时文字选中
return false;
}
}
</script>
实战心得:最难得莫过于交换过程中如何更改两个盒子的位置。如果提前知道思路当然很快就能想起来解决方法,但是难就难在你的动动手慢慢实践出来,出来之后记住类似的套路。
每个盒子的 li 的定位采用横着排的求余,竖着排的除。for 循环出现的 i 就是改变位置的关键,让 i 绑定到元素上。这时候就可以给元素一个 index 属性,当需要交换位置的时候就可以专心的交换盒子元素属性值。这也算是闭包的最佳实践应用。