前端提高篇(七十三):Drag和Drop拖放操作:拖放事件与dataTransfer对象操作

拖放API基础

drag:被拖放元素 在拖拽的过程中触发
dragend 被拖放元素 拖拽完成时
dragenter 目标元素 拖放元素进入目标元素时
dragover 目标元素 拖放元素在目标元素上时
dragleave 目标元素 拖放元素在目标元素上离开
drop 目标元素 被拖放的元素在目标元素上同时鼠标放开触发的事件
注:需要阻止dragover的默认行为才会触发drop事件


被拖拽的元素上需要设置属性:draggable="true",才能被拖拽
被拖拽的元素有三个事件,分别是:dragstart开始拖拽、drag正在拖拽、dragend拖拽结束(鼠标抬起)

验证一下这三个事件:

<style>
    .drag {
        width: 50px;
        height: 50px;
        background: #ccc;
        border-radius: 10px;
        text-align: center;
        line-height: 50px;
    }
    .target {
        width: 300px;
        height: 300px;
        border: 1px dashed #000;
        position: absolute;
        top: 0;
        right: 0;
    }
</style>
<div class="drag" draggable="true">drag</div>
<div class="target">target</div>
<script>
    var drag = document.getElementsByClassName('drag')[0],
        target = document.getElementsByClassName('target')[0];
        
    drag.addEventListener('dragstart',function(){
        console.log('dragstart');
    })
    drag.addEventListener('drag',function(){
        console.log('drag');
    })
    drag.addEventListener('dragend',function(){
        console.log('dragend');
    })
</script>

效果:
当鼠标点击被拖拽元素时,触发dragstart事件,输出’dragstart’;
拖拽过程中,触发drag事件,输出’drag’;
鼠标抬起,拖拽结束,触发dragend事件,输出’dragend’
在这里插入图片描述
目标元素可绑定的事件有:dragenter,dragover,dragleave,drop
验证一下前三个

dragenter事件以鼠标位置为准,当鼠标进入目标元素范围,触发dragenter;鼠标离开目标元素范围,触发dragleave,或者鼠标抬起,被拖拽元素完全离开目标元素范围

target.addEventListener('dragenter',function(){
    console.log('dragenter');
})

target.addEventListener('dragover',function(){
    console.log('dragover');
})

target.addEventListener('dragleave',function(){
    console.log('dragleave');
})

鼠标点在被拖拽元素最左上角时,当鼠标移入target区域,dragenter才触发,鼠标未进入,被拖拽元素进入大半部分了,也还没有触发dragenter事件;
鼠标点在被拖拽元素右边部分时,当鼠标进入target区域,被拖拽元素仅有小部分进入target范围,就已经触发了dragenter事件;
鼠标离开target区域,触发dragleave事件,或者在target区域放开鼠标,触发dragleave事件

在这里插入图片描述

drop事件
在上一个例子中可以看到,鼠标在target区域放开,自动触发的是dragleave事件,被拖拽元素回到原位置,没有保留在鼠标松开的位置,这时候需要解除dragover的默认行为(即dragleave),触发drop事件,允许放置文件

target.addEventListener('dragenter',function(){
    console.log('dragenter');
})

target.addEventListener('dragover',function(e){
    e.preventDefault();//取消dragover的默认行为
    console.log('dragover');
})

target.addEventListener('dragleave',function(){
    console.log('dragleave');
})

target.addEventListener('drop',function(){
    console.log('drop');
})

可以看到,鼠标在target区域松开,触发的不再是dragleave事件,而是drop
在这里插入图片描述
然后我就可以操作dom元素,当把元素拖到trarget范围内并drop时,让这个元素留在target中

target.addEventListener('drop',function(){
    this.appendChild(drag);
    //此处的this指target,是target绑定的事件,当事件触发,由target执行相应的处理函数
})

效果:
在这里插入图片描述
如果我有两个需要拖拽的元素,就需要判断是哪个元素被拖过来了,然后将这个元素append到target下

这时候,就需要使用dataTransfer对象了

dataTransfer对象:
1.getData()向dataTransfer对象中存放数据
2.setData() 从dataTransfer对象中读取数据

var drag = document.getElementsByClassName('drag')[0],
    drag2 = document.getElementsByClassName('drag2')[0],
    target = document.getElementsByClassName('target')[0];

//被拖拽元素    
drag.addEventListener('dragstart',function(e){
    var dt = e.dataTransfer;
    dt.setData('className',this.className);//这里的this指的是drag
})
drag2.addEventListener('dragstart',function(e){
    var dt = e.dataTransfer;
    dt.setData('className',this.className);
})

//目标元素
target.addEventListener('dragover',function(e){
    e.preventDefault();//取消dragover的默认行为
})
target.addEventListener('drop',function(e){

    var dt = e.dataTransfer;
    var dataName = dt.getData('className');
    this.appendChild(document.getElementsByClassName(dataName)[0]);
})

效果:
在这里插入图片描述

拖放小demo:把元素拖到目标位置删除,效果如下:
在这里插入图片描述
思路:给要删除的每个元素绑定dragstart事件,把索引值传到dataTransfer对象中,drop获取到这个索引值,找到对应dom元素,删除
注意:使用for循环绑定监听时,会构成闭包,遍历的i值不会立即传到dataTransfer中,只是累加,当触发dragstart事件时,i都是5

body,
ul,
li {
    margin: 0;
    padding: 0;
    list-style: none;
}

li {
    width: 100px;
    height: 50px;
    background: #ccc;
    text-align: center;
    line-height: 50px;
    margin: 10px 0;
}

.target {
    width: 300px;
    height: 300px;
    background: black;
    color: #fff;
    font-size: 20px;
}
<ul>
    <li class="item1" draggable="true">item1</li>
    <li class="item2" draggable="true">item2</li>
    <li class="item3" draggable="true">item3</li>
    <li class="item4" draggable="true">item4</li>
    <li class="item5" draggable="true">item5</li>
</ul>
<div class="target">删除列表</div>
<script>
    var item = document.getElementsByTagName('li'),
        target = document.getElementsByClassName('target')[0],
        len = item.length;//每执行一次for循环,都获取一次length,耗性能;在开头获取一次,后面调用即可

	//给每个被拖拽元素绑定事件
    function bindListernEvent() {
        for (var i = 0; i < len; i++) {
            (function (j) {
                item[j].addEventListener('dragstart', function (e) {
                    var dt = e.dataTransfer;
                    dt.setData('index', j);
                })
            }) (i)//为避免闭包带来的影响,使用立即执行函数
            //每个li都绑定监听dragstart事件,只有dargstart事件发生时,才会执行后面的函数
            //若for循环下直接写绑定代码,页面刷新,就开始for循环,虽然i一直增加,但绑定的函数并没有执行,因此,i直到最后,都没有真的传到dadaTransfer中
            //当触发这个事件真的需要i时,每个li都传了5进去
            //使用立即执行函数,每循环一次,就执行一次绑定

        }
    }

	//给每个目标元素绑定事件,移除被拖拽元素
    function bindRemoveEvent() {
        target.addEventListener('dragover', function (e) {
            e.preventDefault();
        })
        target.addEventListener('drop', function (e) {
            var dt = e.dataTransfer;
            var index = dt.getData('index');
            console.log(index);
            item[index].remove();
        })
    }

    bindListernEvent();//为了代码的整洁,封装成函数
    bindRemoveEvent();

</script>

在此基础上再增加一个小功能,当一个li覆盖到另一个li,这个li就换位置
在这里插入图片描述

这样每个li也是拖拽操作的目标了
注意:每次把li换位置,index也跟着变了,所以,要想获取新的index值,就需要另外寻找,不再是按顺序了

<script>
    var item = document.getElementsByTagName('li'),
        target = document.getElementsByClassName('target')[0],
        len = item.length,
        ul = document.getElementsByTagName('ul')[0];


    function bindListernEvent() {
        for (var i = 0; i < len; i++) {
            (function(j){
                item[j].addEventListener('dragstart', function (e) {
                var index = findIndex(this, item);//查找当前元素在ul中的位置
                var dt = e.dataTransfer;
                dt.setData('index', index);
            })
            })(i)
            
            item[i].addEventListener('dragover', function (e) {
                e.preventDefault();
            })
            item[i].addEventListener('drop', function (e) {
                var dt = e.dataTransfer;
                var index = dt.getData('index');//第index+1个元素拖拽到当前元素上
                console.log(index);
                ul.insertBefore(item[index], this);//将item[index]放到当前元素的前面
            })
        }
    }

    function bindRemoveEvent() {
        target.addEventListener('dragover', function (e) {
            e.preventDefault();
        })
        target.addEventListener('drop', function (e) {
            var dt = e.dataTransfer;
            var index = dt.getData('index');
            console.log(index);
            item[index].remove();
        })
    }

    bindListernEvent();
    bindRemoveEvent();

    /*
    * 查找当前li元素在ul中的位置
    */
    function findIndex(dom, list){
        for(var i = 0; i <len; i++){
            if (list[i] == dom){
                return i;
            }
        }
    }

</script>
  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,以下是一个简单的HTML 5拖放实例: ```html <!DOCTYPE html> <html> <head> <title>HTML 5拖放实例</title> <style> #div1 { width: 200px; height: 200px; padding: 10px; border: 1px solid black; } </style> <script> function allowDrop(event) { event.preventDefault(); } function drag(event) { event.dataTransfer.setData("text", event.target.id); } function drop(event) { event.preventDefault(); var data = event.dataTransfer.getData("text"); event.target.appendChild(document.getElementById(data)); } </script> </head> <body> <h2>拖动这个文本框到方框中</h2> <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div> <br> <input type="text" id="drag1" draggable="true" ondragstart="drag(event)"> </body> </html> ``` 在这个实例中,我们创建了一个文本框和一个方框,文本框可以被拖动到方框中。实现这个功能的关键是使用了HTML 5的拖放事件,包括`ondragstart`、`ondragover`和`ondrop`事件。 当我们开始拖动文本框时,会触发`ondragstart`事件,这个事件中我们使用了`event.dataTransfer.setData()`方法设置了数据类型和数据内容。在这个例子中,我们将数据类型设为"text",数据内容为文本框的id。 当我们将文本框拖动到方框上时,会触发`ondragover`事件。在这个事件中,我们使用了`event.preventDefault()`方法来防止默认的操作(例如在浏览器中打开被拖动的元素)发生。 当我们在方框中放下文本框时,会触发`ondrop`事件。在这个事件中,我们使用了`event.preventDefault()`方法来防止默认的操作(例如在浏览器中打开被拖动的元素)发生。然后,我们使用`event.dataTransfer.getData()`方法获取了被拖动元素的id,并将其添加到方框中。 这个实例只是一个简单的演示,但是HTML 5的拖放功能非常强大,可以在实际的应用中发挥很大的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值