zoukankan      html  css  js  c++  java
  • 合并元素

    背景:

      前两天面试的时候被问到,元素的拖放应该怎么实现,同时元素的自动合并应该怎么实现(当两个元素的XY轴差距比较小的时候,忽略差距,两元素自动合并);自己之前只写过元素的拖动,并没有写过元素的自动合并,所以就尝试写了一下这个局部。(后话:但是回答不怎么样,只答道了使用CSS属性去判断,并没有将具体思路说明出来)

     

    原理:

      元素拖动:元素拖动的原理其实比较简单,只需要在元素被触发 mousemove 事件时,持续捕获鼠标的位置,然后计算赋值给元素即可

      元素合并:元素合并其实本质上就是抓住合并的条件,然后对所有元素(并不是页面上所有元素,一般能合并的元素都有特定的空间,我们只需要在判断特定空间中的元素是否符合合并条件即可)进行判断。

      具体的实现思路可参照下面代码。

     

    实现代码:

      1 <!DOCTYPE html>
      2 <html>
      3 
      4 <head>
      5     <meta charset="utf-8">
      6     <title>移动元素</title>
      7 <style>
      8     .box {
      9         width: 900px;
     10         height: 700px;
     11         margin: 0 auto;
     12         position: relative;
     13         border: black solid 1px;
     14     }
     15     .box > div {
     16         width: 90px;
     17         height: 60px;
     18         border: black solid 1px;
     19         position: absolute;
     20         text-align: center;
     21         line-height: 60px;
     22         box-sizing: border-box;
     23         cursor: pointer;
     24     }
     25     .element-1 {
     26         background: yellow;
     27         z-index: 100;
     28     }
     29     .element-2 {
     30         background: blue;
     31         z-index: 100;
     32     }
     33     .element-3 {
     34         background: chartreuse;
     35         z-index: 100;
     36     }
     37     .element-4 {
     38         background: red;
     39         z-index: 100;
     40     }
     41 
     42 
     43 </style>
     44 </head>
     45 
     46 <body>
     47     <div class="box">
     48         <div class="element-1">1</div>
     49         <div class="element-2">2</div>
     50         <div class="element-3">3</div>
     51         <div class="element-4">4</div>
     52     </div>
     53     <script>
     54         const returnNumber = (num) => {
     55             let x = num.indexOf('p')
     56             return Number(num.slice(0, x))
     57         }
     58         // 给temp元素绑定事件,使该元素能够被鼠标拖动
     59         const bindEventForMovingElement = (temp) => {
     60             let ele = temp
     61             let element = null
     62             let differX = 0
     63             let differY = 0
     64             let width = returnNumber(window.getComputedStyle(ele).getPropertyValue('width'))
     65             let height = returnNumber(window.getComputedStyle(ele).getPropertyValue('height'))
     66             let controlX = 10
     67             let controlY = 20
     68 
     69             // 在元素被拖动期间,分为三个阶段(本质是触发的三个类型事件)
     70             // mousedown:按下鼠标时触发
     71             // mousemove:拖动鼠标时触发
     72             // mouseup:松开鼠标时触发
     73 
     74             // 在 mousedown 事件中,主要是完成一些前期准备工作
     75             ele.addEventListener('mousedown', function (event) {
     76                 let self = event.target
     77                 // event 可以理解为发生某一事件的位置,event.target表示发生某一事件的元素
     78                 // (differX, differY) 在这里该坐标表示的是鼠标的坐标
     79                 // 这里之所以要记录是因为希望在拖动的过程中,鼠标相对于拖动元素的位置不发生改变
     80                 differX = event.clientX - self.offsetLeft
     81                 differY = event.clientY - self.offsetTop
     82                 // 给element元素赋值,该值为被拖动的元素
     83                 element = event.target
     84             })
     85 
     86             // 在 mousemove 事件中,主要是完成元素移动的事件,即鼠标移动,元素也跟着移动
     87             // 需要注意的是,该功能实现的前提是 CSS 属性必须满足要求,必须是绝对定位以及有对照布局的元素
     88             ele.addEventListener('mousemove', function (event) {
     89                 // 注意,这里是给元素绑定了一个 mousemove 事件,如果不使用 element控制赋值,那么每次鼠标移入该元素均会触发
     90                 if (element !== null) {
     91                     // 下面的 event.clientX, event.clientY 保证了鼠标相对于元素的位置不发生改变
     92                     // 可以去除 differX, differY 两个属性看一下效果
     93                     element.style.left = (event.clientX - differX) + 'px'
     94                     element.style.top = (event.clientY - differY) + 'px'
     95 
     96                     // element.style.left = event.clientX + 'px'
     97                     // element.style.top = event.clientY + 'px'
     98                 }
     99             })
    100 
    101             // 在 mouseup 事件中主要是完成 element 元素的释放内存,表示移动元素事件结束
    102             // 同时在该事件中也可以给元素绑定事件,使元素能够与其他元素合并
    103             ele.addEventListener('mouseup', function (event) {
    104                 element = null
    105                 let self = event.target
    106                 // 表示移动元素的 clientX
    107                 let eleLeft = event.target.offsetLeft
    108                 // 表示移动元素的 clientX
    109                 let eleTop = event.target.offsetTop
    110 
    111                 // 合并一般有一些要求,比如两个元素相差距离为 10px
    112                 // 因此我们在完成拖动之后,只需要对于元素周围是否存在相关元素进行判断即可
    113                 // 因为拖动元素模块一般会有一个 box 元素,将所有所有可移动的元素包裹在一起
    114                 // 因此判断是否需要合并,只需要判断 box 元素内的所有元素是否满足合并要求即可
    115                 let otherEle = document.querySelector('.box').children
    116                 for (let i = 0, len = otherEle.length; i < len; i++) {
    117                     if (otherEle[i] != self) {
    118                         let centerX = otherEle[i].offsetLeft
    119                         let centerY = otherEle[i].offsetTop
    120 
    121                         let differX = eleLeft - centerX
    122                         let differY = eleTop - centerY
    123 
    124                         // 横向合并,合并分为两种情况
    125                         if (Math.abs(differX) > width && Math.abs(differX) < (width + controlX) && Math.abs(differY) < controlY) {
    126                             let x = differX > 0 ? (width - differX) : ( - differX - width)
    127                             self.style.left = eleLeft + x + 'px'
    128                             self.style.top = eleTop - differY + 'px'
    129                         }
    130                         // 纵向合并,合并分为两种情况
    131                         if (Math.abs(differY) > height && Math.abs(differY) < (height + controlX) && Math.abs(differX) < controlY) {
    132                             let y = differY > 0 ? (height - differY) : (- differY - height)
    133                             self.style.top = eleTop + y + 'px'
    134                             self.style.left = eleLeft - differX + 'px'
    135                         }
    136                     }
    137                 }
    138             })
    139         }
    140 
    141         let ele = document.querySelectorAll('.box > div')
    142 
    143         for (let i = 0, len = ele.length; i < len; i++) {
    144             bindEventForMovingElement(ele[i])
    145         }
    146     </script>
    147 </body>
    148 
    149 </html>

     

    执行效果:

    代码执行效果图

    参考资料:

      1. JavaScript高级程序设计(第三版)321页

      2. JavaScript高级程序设计(第三版)618页 ~ 622页

  • 相关阅读:
    ubuntu安装打印机驱动
    clang-format的介绍和使用
    [C++面向对象]-C++成员函数和非成员函数
    [Qt2D绘图]-06QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题
    [Qt2D绘图]-05绘图设备-QPixmap&&QBitmap&&QImage&&QPicture
    [Qt2D绘图]-04绘制文字&&绘制路径
    [Qt2D绘图]-03坐标系统之坐标变换
    [Qt2D绘图]-02坐标系统&&抗锯齿渲染
    [Qt2D绘图]-01Qt2D绘图基本绘制和填充
    [Qt插件]-01Qt插件&&提升部件(自定义控件)
  • 原文地址:https://www.cnblogs.com/oulae/p/11227111.html
Copyright © 2011-2022 走看看