好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

原生js实现九宫格拖拽换位

使用原生JS写出一个九宫格,实现九个格子何以拖拽换位的效果,供大家参考,具体内容如下

效果演示

具体思路分析和代码:

图解1:

代码:

?

<!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

查看更多关于原生js实现九宫格拖拽换位的详细内容...

  阅读:75次