原生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 10 Javascript
实现局部遮罩与关闭原理及代码
Feb 04 Javascript
js获取RadioButtonList的Value/Text及选中值等信息实现代码
Mar 05 Javascript
JavaScript学习笔记之内置对象
Jan 22 Javascript
jquery显示loading图片直到网页加载完成的方法
Jun 25 Javascript
JQuery操作textarea,input,select,checkbox方法
Sep 02 Javascript
jquery实现轮播图效果
Feb 13 Javascript
兼容浏览器的js事件绑定函数(详解)
May 09 Javascript
Vue波纹按钮组件制作
Apr 30 Javascript
vue实现微信分享链接添加动态参数的方法
Apr 29 Javascript
vue实现的上拉加载更多数据/分页功能示例
May 25 Javascript
微信小程序实用代码段(收藏版)
Dec 17 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
Apache, PHP在Windows 9x/NT下的安装与配置 (一)
2006/10/09 PHP
Wordpress php 分页代码
2009/10/21 PHP
mysql_num_rows VS COUNT 效率问题分析
2011/04/23 PHP
PHP入门教程之自定义函数用法详解(创建,调用,变量,参数,返回值等)
2016/09/11 PHP
Yii2 hasOne(), hasMany() 实现三表关联的方法(两种)
2017/02/15 PHP
IE/FireFox具备兼容性的拖动代码
2007/08/13 Javascript
jquery nth-child()选择器的简单应用
2010/07/10 Javascript
jQuery UI Autocomplete 体验分享
2012/02/14 Javascript
jquery 插件开发 extjs中的extend用法小结
2013/01/04 Javascript
使用jQuery.fn自定义jQuery翻页插件
2013/01/20 Javascript
jquery 实现input输入什么div图层显示什么
2014/06/15 Javascript
jquery实现图片放大镜功能
2015/11/23 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
原生js实现图片放大缩小计时器效果
2017/01/20 Javascript
jQuery实现简单的滑动导航代码(移动端)
2017/05/22 jQuery
基于Vue.js实现tab滑块效果
2017/07/23 Javascript
vue中改变选中当前项的显示隐藏或者状态的实现方法
2018/02/08 Javascript
Jquery滑动门/tab切换实现方法完整示例
2020/06/05 jQuery
解决vue中的无限循环问题
2020/07/27 Javascript
浅谈vue在html中出现{{}}的原因及解决方式
2020/11/16 Javascript
如何使用原生Js实现随机点名详解
2021/01/06 Javascript
Python对文件操作知识汇总
2016/05/15 Python
Python2和Python3中print的用法示例总结
2017/10/25 Python
Python面向对象之继承代码详解
2018/01/29 Python
python pandas.DataFrame.loc函数使用详解
2020/03/26 Python
windows10环境下用anaconda和VScode配置的图文教程
2020/03/30 Python
python中判断文件结束符的具体方法
2020/08/04 Python
Reformation官网:美国女装品牌
2018/09/14 全球购物
STP的判定过程
2012/10/01 面试题
优秀教师主要事迹
2014/02/01 职场文书
幼儿园教师的自我评价范文
2014/09/17 职场文书
县级领导干部开展党的群众路线教育实践活动工作汇报
2014/10/25 职场文书
计算机实训报告范文
2014/11/05 职场文书
中秋节祝酒词
2015/08/12 职场文书
星际争霸:毕姥爷vs解冻01
2022/04/01 星际争霸
Windows Server 2019 域控制器安装图文教程
2022/04/28 Servers