原生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 相关文章推荐
JS/FLASH实现复制代码到剪贴板(兼容所有浏览器)
May 27 Javascript
JS自定义功能函数实现动态添加网址参数修改网址参数值
Aug 02 Javascript
Node.js中使用mongoskin操作mongoDB实例
Sep 28 Javascript
node.js中的console.trace方法使用说明
Dec 09 Javascript
在JS中操作时间之getUTCMilliseconds()方法的使用
Jun 10 Javascript
基于JavaScript实现鼠标悬浮弹出跟随鼠标移动的带箭头的信息层
Jan 18 Javascript
Js获取图片原始宽高的实现代码
May 17 Javascript
jquery实现网站列表切换效果的2种方法
Aug 12 Javascript
js获取隐藏元素的宽高
Feb 24 Javascript
详解angular2 控制视图的封装模式
Dec 27 Javascript
深入理解 JS 垃圾回收
Jun 03 Javascript
vue自动添加浏览器兼容前后缀操作
Aug 13 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
第1次亲密接触PHP5(1)
2006/10/09 PHP
PHP下操作Linux消息队列完成进程间通信的方法
2010/07/24 PHP
PHP ? EasyUI DataGrid 资料取的方式介绍
2012/11/07 PHP
php使用cookie实现记住登录状态
2015/04/27 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
php readfile下载大文件失败的解决方法
2017/05/22 PHP
Laravel框架路由和控制器的绑定操作方法
2018/06/12 PHP
jquery.validate使用攻略 第一部
2010/07/01 Javascript
javaScript NameSpace 简单说明介绍
2013/07/18 Javascript
Jquery选中或取消radio示例
2013/09/29 Javascript
onkeyup,onkeydown和onkeypress的区别介绍
2013/10/21 Javascript
js简单的表格添加行和删除行操作示例
2014/03/31 Javascript
js实现点击按钮后给Div图层设置随机背景颜色的方法
2015/05/06 Javascript
jQuery超精致图片轮播幻灯片特效代码分享
2015/09/10 Javascript
详解AngularJs中$sce与$sceDelegate上下文转义服务
2016/09/21 Javascript
JavaScript自定义函数实现查找两个字符串最长公共子串的方法
2016/11/24 Javascript
js实现淡入淡出轮播切换功能
2017/01/13 Javascript
基于js中this和event 的区别(详解)
2017/10/24 Javascript
JS运动特效之链式运动分析
2018/01/24 Javascript
JavaScript面试出现频繁的一些易错点整理
2018/03/29 Javascript
小程序自定义日历效果
2018/12/29 Javascript
[01:42]辉夜杯战队访谈宣传片—FANTUAN
2015/12/25 DOTA
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
Python中set与frozenset方法和区别详解
2016/05/23 Python
python梯度下降法的简单示例
2018/08/31 Python
python3 dict ndarray 存成json,并保留原数据精度的实例
2019/12/06 Python
Python中pyecharts安装及安装失败的解决方法
2020/02/18 Python
Python用Jira库来操作Jira
2020/12/28 Python
HTML5 拖放(Drag 和 Drop)详解与实例代码
2017/09/14 HTML / CSS
Canvas实现保存图片到本地的示例代码
2018/06/28 HTML / CSS
为中国消费者甄选天下优品:网易严选
2016/08/11 全球购物
马来西亚综合购物网站:Lazada马来西亚
2018/06/05 全球购物
Michael Kors加拿大官网:购买设计师手袋、手表、鞋子、服装等
2019/03/16 全球购物
毕业生简单求职信
2013/11/19 职场文书
班级管理经验交流材料
2015/11/02 职场文书
七年级话题作文之执着
2019/11/19 职场文书