实现拖拽

2021-04-20  本文已影响0人  欢欣的膜笛
  1. 原生js实现
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手动实现拖拽</title>
</head>
<style>
    .move {
        position: absolute;
        width: 100px;
        height: 100px;
        background: gray
    }
</style>

<body>
    <div class="move-container">
        <div class="move">
        </div>
    </div>
    <script>
        let elem = document.querySelector('.move');
        let dragging; //拖拽状态
        let trans, portrait; //鼠标按下时相对于选中元素的位移

        document.addEventListener('mousedown', function (e) {
            if (e.target == elem) {
                dragging = true; //激活拖拽状态
                let elemRect = elem.getBoundingClientRect(); //返回元素的大小及其相对于视口的位置
                trans = e.clientX - elemRect.left; //鼠标按下时和选中元素的坐标偏移:x坐标
                portrait = e.clientY - elemRect.top; //鼠标按下时和选中元素的坐标偏移:y坐标
            }
        });
        document.addEventListener('mouseup', function (e) {
            dragging = false;
        });
        document.addEventListener('mousemove', function (e) {
            if (dragging) {
                var moveX = e.clientX - trans,
                    moveY = e.clientY - portrait;

                elem.style.left = moveX + 'px';
                elem.style.top = moveY + 'px';

            }
        });
    </script>
</body>

</html>
  1. HTML5原生实现:拖拽draggable属性、DataTranfers对象
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手动实现拖拽</title>
</head>
<style>
    .main {
        display: flex;
        justify-content: space-around;
    }

    .left {
        margin-right: 10px;
        padding: 1px;
        width: 300px;
        height: 500px;
        text-align: center;
        box-sizing: border-box;
        border: 1px solid red;
    }

    .right {
        padding: 1px;
        width: 300px;
        height: 500px;
        text-align: center;
        box-sizing: border-box;
        border: 1px solid lightseagreen;
    }

    .txt {
        margin: 1px;
        padding: 5px;
        border: 1px solid gray;
        cursor: move;
    }
</style>

<body>
    <main class="main">
        <div class="left" id="left">
            <div class="txt-show">左边区域</div>
            <div id='txt1' draggable="true" class="dragable txt txt1">可移动的文字一</div>
            <div id='txt2' draggable="true" class="dragable txt txt2">可移动的文字二</div>
            <div id='txt3' draggable="true" class="dragable txt txt3">可移动的文字三</div>
            <div id='txt4' draggable="true" class="dragable txt txt4">可移动的文字四</div>
            <div id='txt5' draggable="true" class="dragable txt txt5">可移动的文字五</div>
        </div>
        <div class="right" id='right'>
            <div class="txt-show">右边区域</div>
        </div>
    </main>

    <script>
        /*
         * 注意: 为了让元素可拖动,需要使用 HTML5 draggable 属性。
         * 提示: 链接和图片默认是可拖动的,不需要 draggable 属性。
         * 
         * 在拖放的过程中会触发以下事件:
         * 
         * 在拖动目标上触发事件 (源元素):
         *  ondragstart - 用户开始拖动元素时触发
         *  ondrag - 元素正在拖动时触发
         *  ondragend - 用户完成元素拖动后触发
         * 
         * 释放目标时触发的事件:
         *  ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件
         *  ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
         *  ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件
         *  ondrop - 在一个拖动过程中,释放鼠标键时触发此事件
        */

        let txtList = document.getElementsByClassName('txt')
        for (let i = 0; i < txtList.length; i++) {
            txtList[i].ondragstart = handle_start
            txtList[i].ondrag = handle_drag
            txtList[i].ondragend = handle_end
        }

        function handle_start(e) {
            /*
             * dataTransfer.setData() 方法设置被拖数据的数据类型和值
             * Text 是一个 DOMString,表示要添加到 drag object 的拖动数据的类型。值是可拖动元素的 id ("drag1")
            */
            e.dataTransfer.setData('Text', e.target.id)
            console.log(e.target.id, 'handle_start-拖动开始')
        }

        function handle_drag(e) {
            console.log(e.target.id, 'handle_drag-拖动中')
        }

        function handle_end(e) {
            console.log(e.target.id, 'handle_end-拖动结束')
        }

        let target = document.getElementById('right')
        target.ondragenter = handle_enter
        target.ondragover = handle_over
        target.ondragleave = handle_leave
        target.ondrop = handle_drop

        function handle_enter(e) {
            e.preventDefault()
            console.log(e.target.id, 'handle_enter-进入目的地')
        }

        function handle_over(e) {
            /*
             * ondragover 事件规定在何处放置被拖动的数据。
             * 默认地,无法将数据/元素放置到其他元素中。
             * 如果需要设置允许放置,我们必须阻止对元素的默认处理方式:event.preventDefault()。
             * 
            */
            e.preventDefault()
            let returnObj = e.dataTransfer.getData('Text')
            console.log(returnObj + '-handle_over-在目的地范围内')
        }

        function handle_leave(e) {
            e.preventDefault()
            let returnObj = e.dataTransfer.getData('Text')
            console.log(returnObj + 'handle_leave-没有放下就离开目的地')
        }

        function handle_drop(e) {
            /*
             * 调用 preventDefault() 来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开)
             * 通过 dataTransfer.getData("Text") 方法获得被拖的数据
             * 该方法将返回在 setData() 方法中设置为相同类型的任何数据
             * 把被拖元素追加到放置元素(目标元素)中
            */
            e.stopPropagation() // 不再派发事件。解决Firefox浏览器,打开新窗口的问题。
            e.preventDefault()
            let returnObj = e.dataTransfer.getData('Text')
            if (returnObj) {
                e.target.appendChild(document.getElementById(returnObj))
            }
            console.log(returnObj + '-handle_drop-在目的地区释放')
        }
    </script>
</body>

</html>
上一篇 下一篇

猜你喜欢

热点阅读