利用JavaScript(JS)实现一个九宫格拖拽功能
Demo实现了对任意方格进行拖拽,可以交换位置,其中Demo-1利用了勾股定理判断距离!
Demo-1整体思路:
1.首先div实现自由移动,一定需要脱离标准文档流,所以我们给它使用绝对定位。
2.利用视觉欺骗,点击鼠标悬浮的其实是利用JS生成的一个Div,交换信息的两个Div并没有位置交换,只是把双方属性进行了交换。
3.利用了勾股定理去判断距离。
##效果图如下:
网页源代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>九宫格拖拽</title> </head> <style type="text/css"> #content{ 300px; height:300px; margin: 0 auto; background: #F47564; position: relative; } #content div{ 100px; height: 100px; float: left; line-height: 100px; text-align: center; font-size:40px; font-weight: 900; color: #fff; cursor: pointer; position: absolute; } #content div:nth-child(1){ background-color: #f05b72; top:0; left: 0; } #content div:nth-child(2){ background-color: #faa755; top:0; left:100px; } #content div:nth-child(3){ background-color: #2585a6; top:0; left: 200px; } #content div:nth-child(4){ background:#5ce4fd; top:100px; left: 0; } #content div:nth-child(5){ background:#f61acf; top:100px; left: 100px; } #content div:nth-child(6){ background:#3ef9bd; top:100px; left: 200px; } #content div:nth-child(7){ background:#9af93e; top:200px; left: 0; } #content div:nth-child(8){ background:#eef93e; top:200px; left: 100px; } #content div:nth-child(9){ background:#f9843e; top:200px; left:200px; } #content .draging{ position: absolute; } </style> <body> <div id="content"> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> <div>6</div> <div>7</div> <div>8</div> <div>9</div> </div> <script type="text/javascript"> var content = document.getElementById('content'); var items = content.querySelectorAll('div'); console.log(items); function itemBox(itemName){ itemName.onmousedown = function(evt1){ var e = evt1 || window.event; //在鼠标点下item的时候克隆一个新的一模一样的名为cloneDiv var cloneDiv = document.createElement('div'); //把样式文字赋给克隆div cloneDiv.innerHTML = itemName.innerHTML; cloneDiv.style.backgroundColor = getComputedStyle(itemName).backgroundColor; //使克隆div的class名为draging,使克隆div加绝对定位position:absolute cloneDiv.className = 'draging'; //克隆div的定位top left 和原div相同 cloneDiv.style.top = itemName.offsetTop +'px'; cloneDiv.style.left = itemName.offsetLeft+'px' //把kelongdiv加入到concent大盒子当中 content.appendChild(cloneDiv); //算出鼠标点击克隆div时,鼠标在克隆div中的相对位置 var offsetX = evt1.pageX - cloneDiv.offsetLeft; var offsetY = evt1.pageY - cloneDiv.offsetTop; // cloneDiv.style.zIndex = 10; //鼠标开始移动的时候 document.onmousemove = function(evt){ var e2 = evt || window.event; //克隆div定位的left top evt.pageX鼠标点相对于整个文档中的位置, offsetX鼠标相对于克隆div中的位置 二者相减就是克隆div相对于整个文档中的位置 cloneDiv.style.left = evt.pageX - offsetX +'px'; cloneDiv.style.top = evt.pageY -offsetY+'px' } //当鼠标松开的时候 document.onmouseup = function(){ //先把移动事件停止 document.onmousemove = null; //需要判断 clonediv 的位置距 那个div 最近 //先获取到content大盒子下所有的div var divs = content.getElementsByTagName('div'); console.log(divs.length) //然后判断移动到位置距离哪一个最近 var min = 800;//考虑到被拖拽的div拖拽到大盒子之外还能进行交换,距离设为大盒子外 方圆800px var minDiv = null;//设一个空的div用来交换位置 for(var i=0;i<divs.length-1;i++){//遍历出除了鼠标移动的div外的所有的div 也就是length - 1 var div = divs[i]; //div cloneDiv //distance(cloneDiv,div)返回值为c,c为两div之间的距离 var dis = distance(cloneDiv,div);//调用运用勾股定理进行比较距离的函数 if(dis <= min){//a^2 + b^2 和c^2比较 min = dis; minDiv = div; } } //把距离小的那个div的样式给拖拽走空出来的div itemName //如果这样赋值的话target的innerHTML就会丢失都变成minDiv.innerHTML,所以的设一个中转变量,让两者交换。background同理 // minDiv.innerHTML = target.innerHTML; //两者样式交换,引入第三变量tmpInnerHTMl var tmpInnerHTMl = minDiv.innerHTML; minDiv.innerHTML = itemName.innerHTML; itemName.innerHTML = tmpInnerHTMl; //引入第三变量tmpColor var tmpColor = getComputedStyle(minDiv).backgroundColor; minDiv.style.backgroundColor = getComputedStyle(itemName).backgroundColor; itemName.style.backgroundColor = tmpColor; //删掉克隆元素 content.removeChild(cloneDiv) document.onmouseup = null;//把鼠标松开后的操作清除 } return false; } } //for循环使每一个item都调用itemBox()这个函数 for(var i = 0; i < items.length; i++){ itemBox(items[i]); } function distance(div1,div2) { //勾股定理 记录 两个元素的距离 var a = div1.offsetLeft - div2.offsetLeft; var b = div1.offsetTop - div2.offsetTop; var c = Math.sqrt(a*a+b*b); //利用勾股定理算出两个div的距离 a^2 + b^2 再开平方得出c return c; } </script> </body> </html>
Demo-2整体思路(页面存在很多Bug,提供另一种思路,建议使用Demo1的方法):
1.首先div实现自由移动,一定需要脱离标准文档流,所以我们给它使用绝对定位。
2.利用每个div方块都有相对的坐标值,当鼠标按下移动元素的时候,靠近哪个坐标值,靠近坐标值对应的方块就与当前元素进行位置交换。
3.当前demo,只能存在的bug:元素只能进行交换一次,第二次交换时会发生div被覆盖的结果,不过也提供了另一种思路。
##效果图如下:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>九宫格</title> <style> /*CSS样式设置*/ /*为了方便查看使用通配符去除默认样式,实际开发不建议使用*/ * { margin: 0; padding: 0; } #list { 390px; height: 390px; margin: 90px auto 0; border-radius: 10px; display: flex; flex-flow: wrap; position: relative; /*让div中文字无法被选取,防止因鼠标滑过选取文字而导致鼠标失去焦点*/ -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } /*需要给移动的div设置绝对定位,使其脱离标准文档流*/ div>div { 130px; height: 130px; font-size: 50px; line-height: 130px; border-radius: 8px; color: #fff; text-align: center; font-weight: bold; box-sizing: border-box; cursor: move; position: absolute; } #d1 { top: 0; left: 0; background-color: #f05b72; } #d2 { background-color: #faa755; top: 0; left: 130px; } #d3 { top: 0; left: 260px; background-color: #2585a6; } #d4 { top: 130px; left: 0; background-color: #50b7c1; } #d5 { top: 130px; left: 130px; background-color: #69541b; } #d6 { top: 130px; left: 260px; background-color: #8552a1; } #d7 { top: 260px; left: 0; background-color: #274d3d; } #d8 { top: 260px; left: 130px; background-color: #73b9a2; } #d9 { top: 260px; left: 260px; background-color: #7fb80e; } </style> </head> <body> <div id="list"> <div id="d1">1</div> <div id="d2">2</div> <div id="d3">3</div> <div id="d4">4</div> <div id="d5">5</div> <div id="d6">6</div> <div id="d7">7</div> <div id="d8">8</div> <div id="d9">9</div> </div> </body> <script> // 首先获取每个div的ID,声明变量 var list = document.getElementById("list") var d1 = document.getElementById("d1"); var d2 = document.getElementById("d2"); var d3 = document.getElementById("d3"); var d4 = document.getElementById("d4"); var d5 = document.getElementById("d5"); var d6 = document.getElementById("d6"); var d7 = document.getElementById("d7"); var d8 = document.getElementById("d8"); var d9 = document.getElementById("d9"); // 封装函数,方便后续使用 function box (divname) { // 当在divname上点下鼠标发生的事件 divname.onmousedown = function (env) { // 在div移动前先获取每个传入的实参(divname)的位置,留作位置判断失败后返回原位置 var a1x = divname.offsetLeft; var a1y = divname.offsetTop; console.log(a1x+"这是") console.log(a1y+"这是") // 给每个传入的实参(divname)设置层级,不然会被其他div遮挡住 divname.style.zIndex = "4"; // env代表事件的状态,设置兼容。 var env = env || window.event; // 获取鼠标当被点击的在div上的位置: // env.clientX(代表当前鼠标距离屏幕左边的位置)。 // list.offsetLeft(代表list盒子距离屏幕的左边的位置)。 // 因为divname设置了绝对定位,所以divname.offsetLeft的参数代表鼠标在div上距离父元素的位置 // (env.clientX - list.offsetLeft - divname.offsetLeft)相当于把鼠标当前位置设置为原点 var divmosue_x = (env.clientX - list.offsetLeft - divname.offsetLeft); var divmosue_y = (env.clientY - list.offsetTop - divname.offsetTop); // 当在divname上点下鼠标发生并且鼠标在指定的元素中移动 divname.onmousemove = function (env) { var env = env || window.event; // 获取鼠标当被点击移动的时候在div上的位置: // env.clientX(代表当前鼠标距离屏幕左边的位置)。 // divmosue_x的含义参照上条注释 // list.offsetLeft(代表list盒子距离屏幕的左边的位置)。 // div_x的含义相当于把鼠标当前坐标点设置为原点 var div_x = env.clientX - divmosue_x - list.offsetLeft; var div_y = env.clientY - divmosue_y - list.offsetTop; // 因为divname设置了绝对定位,下面让divname的位置随着鼠标的移动而发生变化 divname.style.top = div_y+"px" divname.style.left = div_x+"px" // 当鼠标松开时的事件,移动的div根据if判断坐标位置,让div符合要求的div交换位置。 // 并让移动后的双方层级为1,防止元素层级遮挡 divname.onmouseup = function () { if (div_x > -65 && div_x < 0 && div_y > -65 && div_y < 0) { d1.style.top = a1y + "px"; d1.style.left = a1x +"px"; divname.style.top = "0px"; divname.style.left = "0px" d1.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > 65 && div_x < 130 && div_y > -65 && div_y < 0) { d2.style.top = a1y + "px"; d2.style.left = a1x +"px"; divname.style.top = "0px" divname.style.left = "130px" d2.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > 190 && div_x <255 && div_y > -65 && div_y < 0) { d3.style.top = a1y + "px"; d3.style.left = a1x +"px"; divname.style.top = "0px" divname.style.left = "260px" d3.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > -65 && div_x < 0 && div_y > 65 && div_y < 130) { d4.style.top = a1y + "px"; d4.style.left = a1x +"px"; divname.style.top = "130px" divname.style.left = "0px" d4.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > 65 && div_x < 130 && div_y > 65 && div_y < 130) { d5.style.top = a1y + "px"; d5.style.left = a1x +"px"; divname.style.top = "130px" divname.style.left = "130px" d5.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > 190 && div_x <255 && div_y > 65 && div_y < 130) { d6.style.top = a1y + "px"; d6.style.left = a1x +"px"; divname.style.top = "130px" divname.style.left = "260px" }else if (div_x > -65 && div_x < 0 && div_y > 190 && div_y < 255) { d7.style.top = a1y + "px"; d7.style.left = a1x +"px"; divname.style.top = "260px" divname.style.left = "0px" d5.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > 65 && div_x < 130 && div_y > 190 && div_y < 255) { d8.style.top = a1y + "px"; d8.style.left = a1x +"px"; divname.style.top = "260px" divname.style.left = "130px" d8.style.zIndex = "1"; divname.style.zIndex = "1"; }else if (div_x > 190 && div_x <255 && div_y > 190 && div_y < 255) { d9.style.top = a1y + "px"; d9.style.left = a1x +"px"; divname.style.top = "260px" divname.style.left = "260px" d9.style.zIndex = "1"; divname.style.zIndex = "1"; } // 如果divname,未符合判断条件,则让它回到原点位置 else{ console.log("asdsa") console.log(a1x) console.log(a1y) divname.style.top = a1x + "px"; divname.style.left = a1y+"px"; divname.style.zIndex = "1"; divname.onmousemove = null; } divname.onmousemove = null; console.log("松开了"); } } } } box(d1) box(d2) box(d3) box(d4) box(d5) box(d6) box(d7) box(d8) box(d9) </script> </html>
本demo-1参考思路来源于网络,如有侵权,请及时联系删除。