原生JS实现简单的拖放

最近学到了js中的事件,感觉和windows的事件队列和处理函数很相似哈。需要监听事件然后要有处理事件的函数。然后做了一个小练习,元素的拖放。废话不说了,上效果。实现子元素任意框拖放。
原始状态,要实现任意拖放
首先在布局上,三个大盒子中的元素都是绝对定位于他们的父元素,给三个大盒子相对定位。上HTML和CSS代码。

<div id="cnt">
			<div><span>1</span><span>2</span></div>
			<div><span>3</span><span>4</span></div>
			<div><span>5</span><span>6</span></div>
</div>

以上是html代码,比较简单。CSS布局如下:

         * {
				margin: 0;
				padding: 0;
				list-style: none;
			}
			
			#cnt {
				width: 1440px;
				margin: 30px auto;
				text-align: center;
				font-size: 0;
			}
			
			#cnt>div {
				width: 450px;
				height: 360px;
				margin: 0 15px;
				font-size: 20px;
				padding: 0 25px;
				vertical-align: top;
				box-sizing: border-box;
				display: inline-block;
				background: papayawhip;
				position: relative;
			}
			
			#cnt>div>span {
				width: 400px;
				height: 50px;
				line-height: 50px;
				margin: 5px 0;
				display: block;
				color: #fff;
				background: aqua;
				position: absolute;
				z-index: 99;
			}

由于子元素的布局放在js中实现,所以子元素叠在一起,最关键的js代码如下:

            var nthpar = document.querySelectorAll("#cnt>div");//所有的父元素。兼容不太好,最好用谷歌打开
			var nthchild = document.querySelectorAll("#cnt span");
			function addevent() {
				nthchild = document.querySelectorAll("#cnt span");//所有的span子元素
				for(var i = 0; i < nthchild.length; i++) {//遍历添加事件
					(function(num) {
						nthchild[num].onmousedown = function() {
							begaindrag(num);
						};
					})(i);//闭包添加事件,主要是保存num的私有
				}
			}
			function sortchild(){
				for(var i = 0; i < nthpar.length; i++) {//遍历父元素
					var child = nthpar[i].children,pos = 0;//父元素下的子元素,由于每次拖放会改变,子元素要重新获取
					for(var j = 0; j < child.length; j++) {
						child[j].style.top = pos + "px";
						child[j].style.left = "25px";
						pos += child[0].offsetHeight + 5;//top值累加,每个子元素相隔5px
					}
				}
			}
			addevent();//初始化每个子元素添加事件
			sortchild();//初始化布局每个盒子子元素
			var drag = true;//判断拖放状态
			function begaindrag(num) {//鼠标按下事件原型
				drag = true;
				var isout = false;//判断元素是否出了父元素
				var posx = event.pageX - nthchild[num].offsetLeft;//按下时鼠标在元素内部的偏移
				var posy = event.pageY - nthchild[num].offsetTop;
				window.onmousemove = function() {
					if(drag == true) {
						var posx_new = event.pageX - posx;
						//计算出新的left值,实际上是新的pagex-旧的pagex+元素的offset的值,就是新的left值
						var posy_new = event.pageY - posy;
						nthchild[num].style.position = "absolute";
						nthchild[num].style.left = posx_new + "px";//使得被拖放元素跟随鼠标移动
						nthchild[num].style.top = posy_new + "px";
					}
					window.onmouseup = function() {//关键点,判断是否出界,出界后在哪个盒子里
						(Math.abs(posx_new) > Math.abs(nthchild[num].offsetWidth / 2)) && (isout = true);
						//鼠标抬起时元素拖放的left位移超过1/2父元素长度就会判断出界
						if(isout == true) {
							console.log("out");
							var par=nthchild[num].parentElement;//被拖放元素的原始父元素保存起来
							for(var k = 0; k < nthpar.length; k++){//遍历三个父元素判断进到了哪里
								if(nthpar[k] != par && isout != false) {//判断进入哪个盒子,既然出去了,排除原始父元素
									//console.log(Math.abs((nthpar[k+1].offsetLeft - nthchild[num].offsetParent.offsetLeft)*0.75));
									if( 720 < Math.abs(nthchild[num].offsetLeft)){
						//实际上是水平位移超出了1.5个盒子宽度就进入相隔盒子,后来发现访问越界,要加诸多判断,索性给了个常数值
										var state=0;if(nthchild[num].offsetLeft>0){state=1;}
										//state主要是判断被拖放的方向,左or右。根据位移left的正负判断
										console.log("进入相隔");
										var nod = nthchild[num].cloneNode(true);//拷贝被拖放元素
										par.removeChild(nthchild[num]);//从原始父元素移除被拖放元素
										state==1 && par.nextElementSibling.nextElementSibling.appendChild(nod);//根据方向可以判断唯一的被放置的盒子
										state==0 && par.previousElementSibling.previousElementSibling.appendChild(nod);
										isout = false;
									}else 
									if(Math.abs((nthpar[k].offsetLeft - nthchild[num].offsetParent.offsetLeft)/2)<Math.abs(nthchild[num].offsetLeft)){//进入相邻的盒子,具体的操作如上
										var state=0;if(nthchild[num].offsetLeft>0){state=1;}
										console.log("进入相邻"+nthchild[num].offsetLeft);
										var nod = nthchild[num].cloneNode(true);
										par.removeChild(nthchild[num]);
										state==1 && par.nextElementSibling.appendChild(nod);
										state==0 && par.previousElementSibling.appendChild(nod);
										isout = false;
									}
								}
							}
						}
						drag = false;//若是没有拖拽成功不再响应mousemove的事件
						sortchild();//拖放完成后重新排列。如果没有拖出去,重新排列后会回到原位置
						addevent();//重新对子元素添加事件
					}
				}
			}

拖放后
如图可以实现简单的拖放。但是对于越界,和诸多的细节没有更进一步处理。比如第一个盒子中的元素往左移动,会出现访问不到的越界错误。也没有对高度进行进一步的限制。只是给大家提供下思路,希望能帮助到在路上的朋友们(≖ᴗ≖)✧。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值