原生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 Global对象
Aug 13 Javascript
基于jQuery捕获超链接事件进行局部刷新代码
May 10 Javascript
javascript判断office版本示例
Apr 11 Javascript
avalonjs制作响应式瀑布流特效
May 06 Javascript
jQuery的文档处理程序详解
May 10 Javascript
PassWord输入框代码分享
Jun 07 Javascript
jQuery之动画ajax事件(实例讲解)
Jul 18 jQuery
react中实现搜索结果中关键词高亮显示
Jul 31 Javascript
详解create-react-app 2.0版本如何启用装饰器语法
Oct 23 Javascript
解决Layui数据表格的宽高问题
Sep 28 Javascript
jQuery 实现扁平式小清新导航
Jul 07 jQuery
vue中组件通信详解(父子组件, 爷孙组件, 兄弟组件)
Jul 27 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
thinkphp学习笔记之多表查询
2014/07/28 PHP
PDO预处理语句PDOStatement对象使用总结
2014/11/20 PHP
PHP抽奖算法程序代码分享
2015/10/08 PHP
PHP删除数组中指定值的元素常用方法实例分析【4种方法】
2018/08/21 PHP
php封装的pdo数据库操作工具类与用法示例
2019/05/08 PHP
IE Firefox 使用自定义标签的区别
2009/10/15 Javascript
纯js分页代码(简洁实用)
2013/11/05 Javascript
JQuery给元素绑定click事件多次执行的解决方法
2014/05/29 Javascript
javascript闭包的理解
2015/04/01 Javascript
jQuery实现的产品自动360度旋转展示特效源码分享
2015/08/21 Javascript
微信小程序 增、删、改、查操作实例详解
2017/01/13 Javascript
bootstrap multiselect 多选功能实现方法
2017/06/05 Javascript
浅谈react前后端同构渲染
2017/09/20 Javascript
Angular弹出模态框的两种方式
2017/10/19 Javascript
vue采用EventBus实现跨组件通信及注意事项小结
2018/06/14 Javascript
微信小程序如何再次获取用户授权的方法
2019/05/10 Javascript
如何使用Node.js爬取任意网页资源并输出PDF文件到本地
2019/06/17 Javascript
JS数组方法concat()用法实例分析
2020/01/18 Javascript
[01:36]DOTA2完美大师赛趣味视频之与队友相处的十万个技巧
2017/11/19 DOTA
使用Python编写一个最基础的代码解释器的要点解析
2016/07/12 Python
Python 200行代码实现一个滑动验证码过程详解
2019/07/11 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
2019/07/22 Python
python excel转换csv代码实例
2019/08/26 Python
pytorch的batch normalize使用详解
2020/01/15 Python
matplotlib交互式数据光标mpldatacursor的实现
2021/02/03 Python
django使用多个数据库的方法实例
2021/03/04 Python
基于HTML5实现类似微信手机摇一摇功能(计算摇动次数)
2017/07/24 HTML / CSS
机械设计专业应届生求职信
2013/11/21 职场文书
转预备党员政审材料
2014/02/06 职场文书
学习雷锋标语
2014/06/25 职场文书
社团活动总结书
2014/06/27 职场文书
商铺门面租房协议书
2014/10/21 职场文书
2015年毕业实习工作总结
2015/05/29 职场文书
入党积极分子党小组意见
2015/06/02 职场文书
Python 高级库15 个让新手爱不释手(推荐)
2021/05/15 Python
一文搞懂PHP中的抽象类和接口
2022/05/25 PHP