• 视二: 原生JS 实现拖拽&临界值


      今天来说下原生JS如何实现拖拽的功能 —— 只能在可拖拽范围内进行拖拽。实现该功能的思路,就是: 通过改变拖拽元素的位置(left, top)来实现。

      在这个功能中我们需要考虑三个事件和两个临界点。

      拖拽的三事件:

      • 鼠标落下 ——  mousedown
      • 鼠标移动 ——  onmousemove
      • 鼠标抬起 ——  mouseup

      两个临界点:

      • 最小的临界点
      • 最大的临界点

      

      接下来,我们先写好html代码和css  样式。我们定义一个可拖拽的容器 wrapper  和 一个 拖拽框  box。

    // CSS
    *
    { margin: 0; padding: 0; } .wrapper{
       position:relative; width: 500px; height: 500px; margin: 150px auto; border: 1px solid #000; } .box{ position: absolute; width: 200px; height: 200px; background-color: red; cursor: move; }
    // HTML
    <div class="wrapper">
        <div class="box"></div>
    </div>

      HTML 和 CSS 写好了,接下来我们来写JS。

      首先我们要获得到  wrapper  和  box 这个两个元素。采用 document.getElementsByClassName('className')[0]  。为什么要用 [0] ?  因为  getElementByClassName 获取到的是一个类数组的数据。将document.getElementsByClassName('wrapper')打印出来,如下图:

      

      所以需要获取下标为 0  的第一个元素。
     

      接着,我们实现 监听【鼠标落下】的功能,为了后续的【当鼠标移除可拖拽范围】,此处我们先获取 wrapper 元素。

    var wrap= document.getElementByClassName('wrapper')[0],
        oBox = document.getElementByClassName('box')[0]
    
    oBox.addEventListener('mousedown', function(e){
        
         var lastX = e.clientX,
             lastY = e.clientY;
    
    });    

    【鼠标移动】,此时我们要获取鼠标移动所在的坐标,并计算出此时的坐标与上一个坐标的差值。

    解析图如下:鼠标在 a  点位置落下,移动到  b  点,此时需要计算出  移动的垂直和水平距离。

    document.onmousemove = function (e){
    // 此处 ,为什么要用document ? 而不用 oBox ? 如果用 oBox ,当鼠标快速移动的时候,会出现 移动块(box) 脱落,不会跟着鼠标移动。
    // 如果后续设置了鼠标只能在拖拽框中进行拖拽,此处就可以采用 oBox ,但是后面的对应的鼠标移动事件也需要使用 oBox 。
    var nowX = e.clientX, nowY = e.clientY var disX = nowX - lastX, disY = nowY - lastY var left = oBox.offsetLeft + disX, // offsetLeft 是 当前元素距离父级元素的距离 top = oBox.offsetTop + disY }

      在css 中,我们给 wrapper 设置了——相对定位,给 box 元素设置了——绝对定位,此时,我们就可以将 上面代码中的  left  和  top  赋值给  box  元素

    oBox.style.left = left + 'px' 
    oBox.style.top = top + 'px'

    *此时,需要注意的是,拖拽的过程中,鼠标是不停的在移动,所以,此时的初始点  (a)  和 移动终点  (b)  也是在不断的改变,所以我们需要重新给  初始点 a  的水平和垂直距离赋值。

    lastX = nowX
    lastY = nowY

    【鼠标抬起】:鼠标落下和鼠标移动实现了, 那当我们将 box 元素拖拽到目标位置点的时候,此时,我们就需要实现  鼠标抬起  的功能。代码如下:

    document.onmouseup = function(){
        document.onmousemove = null;
    }

    上面实现了拖拽的功能,但是发现 移动块可以满屏的拖,那如果只想要在可拖拽范围内拖拽呢?

    此时就需要考虑临界值的问题。即左上角 和右下角。在鼠标移动事件中,我们增加 left  和 top  取值限制。即当 右下角坐标 >  left / top  > 左上角坐标, 代码如下:

    
    
     var wrapLeft = wrap.getBoundingClientRect().left
     var wrapLeftLast = wrapLeft + 302
    // 最小临界值
    left = left <= wrapLeft ? wrapLeft.left : left
    top = top <= 150 ? 150 : top;
    
    // 最大临界值
    left = left >= wrapLeftLast ? wrapLeftLast : left
    top = top >= (500 - 200 + 152) ? 452 : top;

    此处,因为我给  box 设置了居中,所以采用了 getBoundingClientRect().left  获取  box  左侧距离窗口的距离。如果需求中没有给box 设置,可以直接将 wrapLeft = 0 ,  wrapLeftLast = (wrapper.width  - box.width) 来代替。

    最后,我们再实现上文说的后续功能。当鼠标移出拖拽范围 wrapper 的时候,我们停止拖拽行为。代码如下:

    wrap.onmouseleave = function(e){
        document.onmousemove = null
    }

    好了,思路都解析完了,下面贴上完整的代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            *{
                margin: 0;
                padding: 0;
            }
            .wrapper{
                width: 500px;
                height: 500px;
                margin: 150px auto;
                border: 1px solid #000;
            }
            .box{
                position: absolute;
                width: 200px;
                height: 200px;
                background-color: red;
                cursor: move;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
            <div class="box"></div>
        </div>
        <script>
            var oBox = document.getElementsByClassName('box')[0],
               wrap = document.getElementsByClassName('wrapper')[0],
               wrapLeft = wrap.getBoundingClientRect().left,
               wrapLeftLast = wrapLeft +  302;   // 302 :  考虑了边框 两个像素的问题
    
            oBox.addEventListener('mousedown', function(e){
                var lastX = e.clientX,
                   lastY = e.clientY;
    
                document.onmousemove = function(e){
                    var nowX = e.clientX,
                       nowY = e.clientY;
    
                    var disX = nowX - lastX,
                       disY = nowY - lastY;
    
                    var left = oBox.offsetLeft + disX,
                       top = oBox.offsetTop + disY;
    
                    left = left <= wrapLeft ? wrapLeft.left : left;
                    top = top <= 150 ? 150 : top;
    
                    left = left >= wrapLeftLast ? wrapLeftLast : left;
                    top = top >= (500 - 200 + 152) ? 452 : top;  // 452 考虑了边框两像素的问题
    
                    oBox.style.left = left + 'px';
                    oBox.style.top = top + 'px';
    
                    lastX = nowX;
                    lastY = nowY;
                }
    
                document.onmouseup = function(){
                    document.onmousemove = null
                }
            })
    
            wrap.onmouseleave = function(e){
                document.onmousemove = null
            }
        </script>
    </body>
    </html>
  • 相关阅读:
    CodeForces 446A. DZY Loves Sequences(最长上升子序列)
    CodeForces
    2020牛客暑期多校训练营(第一场)
    POJ3281-Dining(最大流)(拆点)
    「杂题」图论杂题选做
    「学习小结」CDQ 分治多维偏序问题
    「算法笔记」Tarjan 算法 双连通分量
    「算法笔记」状压 DP
    「算法笔记」数位 DP
    「算法笔记」矩阵乘法
  • 原文地址:https://www.cnblogs.com/bala/p/11447676.html
Copyright © 2020-2023  润新知