[js效果]原生JS实现拖拽

思路

  • 被拖拽的元素eDrag要使用绝对定位,脱离文档流才可以移动。

  • 鼠标点击:isDragged(当前eDrag是否被拖拽的标识)设置为true,a= 获取当前鼠标坐标、b = eDrag盒子左上角的坐标、c = 鼠标在div内部距离=a-b=(offsetX, offsetY)。

  • 鼠标移动:通过 b = a – c = a – (a – b) 建立鼠标与eDrag的关系,注意处理盒子到达浏览器边界的情况,防止eDrag超出浏览器。

  • 鼠标抬起:isDragged(当前eDrag是否被拖拽的标识)设置为false

注意要点

  • eDrag.offsetLeft、eDrag.offsetTop分别代表eDrag的盒子的左上角与浏览器视图左边界和上边界的距离,即浏览器左上角为原点(0,0),width为x轴,height为y轴。
  • 鼠标在eDrag内点击时的一刻,鼠标的坐标(x1,y1)与eDrag盒子左上角的坐标(x2,y2),一定有:x1>=x2,y1>=y2。
  • 鼠标移动时,分别针对eDrag左上角坐标b(x,y)的x和y来讨论边界处理的情况。

进阶

使用一个轨迹数组,每次鼠标拖拽时,将当前eDrag的(x,y)存入数组。

实现回放拖拽轨迹

队列的使用,使用Array.prototype.shift()不断从队头(数组头)拿轨迹位置数据。

实现倒放拖拽轨迹

栈的使用,使用Array.prototype.pop()不断从栈尾(数组尾)拿轨迹位置数据。

实现效果

[js效果]原生JS实现拖拽
img

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>

        bodydivh2p {
            margin0;
            padding0;
        }

        body {
            background-color#666666;
        }


        .box {
            /* 必须是绝对定位 */
            position: absolute;

            width300px;
            background: blue;
            cursor: move;
            border2px solid black;

            top50%;
            left50%;
        }

        .box h2 {
            color: white;
            font-size20px;
            line-height1em;
            background-color#222;
            border-bottom2px solid #ccc;
            text-align: center;
            padding0 10px;
        }

        .box p {
            color: white;
        }

        #backtrack {
            border-top1px solid black;
            padding0 10px;
            vertical-align: bottom;
            text-align: right;
        }

        #backtrack a {
            text-decoration: none;
            color: white;
        }

        #backtrack a:hover {
            text-decoration: underline;
            color: black;
        }

        /* 不可点击 */
        .notClick{
             pointer-events: none;
         }

    
</style>
</head>
<body>
<div class="box" id="eDrag">
    <h2>一个寂寞的拖拽框</h2>
    <p><strong>isDragged:</strong><span id="eIsDragged">false</span></p>
    <p><strong>offsetTop:</strong><span id="eOffsetTop">229</span></p>
    <p><strong>offsetLeft:</strong><span id="eOffsetLeft">385</span></p>
    <p id="backtrack">
        <a id="aPlayback" href="javascript:">点此回放拖动轨迹</a>
        <a id="aBacktrack" href="javascript:">点此倒放拖动轨迹</a>
    </p>
</div>

<script>
    // 元素
    let eDrag = document.getElementById('eDrag');  // 拖动框
    let eIsDragged = document.getElementById('eIsDragged');
    let eOffsetTop = document.getElementById('eOffsetTop');
    let eOffsetLeft = document.getElementById('eOffsetLeft');

    let aPlayback = document.getElementById('aPlayback');
    let aBackTrack = document.getElementById('aBacktrack');

    // 鼠标和拖动框的差异的x和y值
    let diffX = 0;
    let diffY = 0;

    // 拖动框当前的状态
    let nowX = eDrag.offsetLeft;
    let nowY = eDrag.offsetTop;
    let isDragged = false;

    // 状态数组
    let positionArray = [
        {
            x: eDrag.offsetLeft,
            y: eDrag.offsetTop,
        }
    ]

    // 更新状态栏   监听状态函数
    function updateShowInfo({
        eIsDragged.innerText = isDragged;
        eOffsetTop.innerText = nowY;
        eOffsetLeft.innerText = nowX;
    }

    // 移动元素
    function moveTarget(target, x, y{
        target.style.left = x + 'px';
        target.style.top = y + 'px';
    }

    // 在拖动框身上按下鼠标时
    eDrag.onmousedown = function (event{
        event = event || window.event;

        isDragged = true;
        diffX = event.clientX - eDrag.offsetLeft;
        diffY = event.clientY - eDrag.offsetTop;


        if (typeof eDrag.setCapture !== "undefined") {
            eDrag.setCapture();
        }
    }

    // 在页面上移动鼠标时
    document.onmousemove = function (event{

        if (!isDragged) {
            return;
        }
        // console.log("拖动中")

        event = event || window.event;

        nowX = event.clientX - diffX;
        nowY = event.clientY - diffY;

        if (nowX < 0) {
            nowX = 0;
        } else if (nowX > window.innerWidth - eDrag.offsetWidth) {
            nowX = window.innerWidth - eDrag.offsetWidth;
        }

        if (nowY < 0) {
            nowY = 0;
        } else if (nowY > window.innerHeight - eDrag.offsetHeight) {
            nowY = window.innerHeight - eDrag.offsetHeight;
        }

        // 放入轨迹数组中
        positionArray.push(
            {
                x: nowX,
                y: nowY,
            }
        )

        // 移动元素
        moveTarget(eDrag, nowX, nowY)

        // 更新显示信息
        // console.log(nowX + 'px', nowY + 'px')
        updateShowInfo();
    }

    // 放开鼠标时
    document.onmouseup = window.onblur = eDrag.onlosecapture = function (event{
        isDragged = false;

        if (typeof eDrag.releaseCapture != "undefined") {
            eDrag.releaseCapture();
        }

        updateShowInfo();
    }

    //正放拖动轨迹
    aPlayback.onclick = function ({
        if (positionArray.length === 1)
            return;

        let timer = setInterval(function ({
            let tmpPos = positionArray.shift();
            if (tmpPos) {
                moveTarget(eDrag, tmpPos.x, tmpPos.y);
            } else {
                clearInterval(timer);
            }
        }, 33);
    };

    //倒放拖动轨迹
    aBackTrack.onclick = function ({
        if (positionArray.length === 1)
            return;

        let timer = setInterval(function ({
            let tmpPos = positionArray.pop();
            if (tmpPos) {
                moveTarget(eDrag, tmpPos.x, tmpPos.y);
            } else {
                clearInterval(timer);
            }

        }, 33);
    };
 
    // 初始化
    updateShowInfo();

</script>
</body>
</html>


原文始发于微信公众号(豆子前端):[js效果]原生JS实现拖拽

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/56806.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!