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


Posted in Javascript onJanuary 26, 2021

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

效果演示

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

具体思路分析和代码:

图解1:

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

代码:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
判断浏览器的javascript版本的代码
Sep 03 Javascript
javascript中substr,substring,slice.splice的区别说明
Nov 25 Javascript
JavaScript自定义DateDiff函数(兼容所有浏览器)
Mar 01 Javascript
JavaScript实现x秒后自动跳转到一个页面
Jan 03 Javascript
jQuery Ajax异步处理Json数据详解
Nov 05 Javascript
JavaScript中实现PHP的打乱数组函数shuffle实例
Oct 11 Javascript
使用jquery插件qrcode生成二维码
Oct 22 Javascript
实例详解jQuery表单验证插件validate
Jan 18 Javascript
Javascript es7中比较实用的两个方法示例
Jul 21 Javascript
JavaScript求一组数的最小公倍数和最大公约数常用算法详解【面向对象,回归迭代和循环】
May 07 Javascript
JavaScript中的this/call/apply/bind的使用及区别
Mar 06 Javascript
VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定的数据不能实时更新)
Apr 03 Javascript
原生JS实现音乐播放器
Jan 26 #Javascript
通过滑动翻页效果实现和移动端click事件问题
Jan 26 #Javascript
全面解析js中的原型,原型对象,原型链
Jan 25 #Javascript
js中实现继承的五种方法
Jan 25 #Javascript
Vue中的nextTick作用和几个简单的使用场景
Jan 25 #Vue.js
Vue使用Ref跨层级获取组件的步骤
Jan 25 #Vue.js
javascript实现点击产生随机图形
Jan 25 #Javascript
You might like
PHP简单实现无限级分类的方法
2016/05/13 PHP
php while循环控制的简单实例
2016/05/30 PHP
js冒泡法和数组转换成字符串示例代码
2013/08/14 Javascript
JavaScript onkeydown事件入门实例(键盘某个按键被按下)
2014/10/17 Javascript
javascript中clone对象详解
2014/12/03 Javascript
javascript使用prototype完成单继承
2014/12/24 Javascript
详细分析JavaScript函数定义
2015/07/16 Javascript
在node.js中怎么屏蔽掉favicon.ico的请求
2017/03/01 Javascript
vue移动UI框架滑动加载数据的方法
2018/03/12 Javascript
webpack4.0 入门实践教程
2018/10/08 Javascript
nodejs读取本地中文json文件出现乱码解决方法
2018/10/10 NodeJs
JavaScript回调函数callback用法解析
2020/01/14 Javascript
Python实现list反转实例汇总
2014/11/11 Python
python使用线程封装的一个简单定时器类实例
2015/05/16 Python
[原创]教女朋友学Python(一)运行环境搭建
2017/11/29 Python
python中列表和元组的区别
2017/12/18 Python
使用python实现ANN
2017/12/20 Python
PyQt4实现下拉菜单可供选择并打印出来
2018/04/20 Python
Django框架实现逆向解析url的方法
2018/07/04 Python
Django 中使用流响应处理视频的方法
2018/07/20 Python
tensorflow实现简单逻辑回归
2018/09/07 Python
windows下Pycharm安装opencv的多种方法
2020/03/05 Python
Python运行提示缺少模块问题解决方案
2020/04/02 Python
Keras loss函数剖析
2020/07/06 Python
Python利用命名空间解析XML文档
2020/08/10 Python
Python如何读写CSV文件
2020/08/13 Python
python线程池 ThreadPoolExecutor 的用法示例
2020/10/10 Python
python实现简单猜单词游戏
2020/12/24 Python
详解matplotlib绘图样式(style)初探
2021/02/03 Python
保密承诺书范文
2014/03/27 职场文书
学雷锋月活动总结
2014/04/25 职场文书
年终晚会活动方案
2014/08/21 职场文书
工作迟到检讨书范文
2015/05/06 职场文书
一年级下册数学教学反思
2016/02/16 职场文书
Spring Boot配合PageHelper优化大表查询数据分页
2022/04/20 Java/Android
JavaScript前端面试扁平数据转tree与tree数据扁平化
2022/06/14 Javascript