HTML5中实现元素拖放竟然如此简单

举报
lwq1228 发表于 2021/08/10 10:56:38 2021/08/10
【摘要】 在HTML5之前,如果想要实现一个元素的拖放效果,我们一般需要结合该元素的onmousedown、onmousemove、onmouseup等多个事件来共同完成。这种方式代码量非常大,而且也仅限于在浏览器内的元素间拖放,不能实现跨应用拖放。在HTML5中,我们只需要给元素添加一个draggable属性,然后设置该属性值为true,就能实现元素的拖放。

1、元素拖放简介

在HTML5之前,如果想要实现一个元素的拖放效果,我们一般需要结合该元素的onmousedown、onmousemove、onmouseup等多个事件来共同完成。这种方式代码量非常大,而且也仅限于在浏览器内的元素间拖放,不能实现跨应用拖放。在HTML5中,我们只需要给元素添加一个draggable属性,然后设置该属性值为true,就能实现元素的拖放。拖放,指的是“拖拽”和“释放”。在页面中进行一次拖放操作,我们必须先弄清楚两个元素:“源元素”和“目标元素”。“源元素”指的是被拖拽的那个元素,“目标元素”指的是源元素最终被释放到的那个元素。HTML5的拖放事件总共有7个,分为两类“源元素”触发的事件和“目标元素”触发的事件,详见下表:

事件类型 事件 说明
“源元素”触发 ondragstart 开始拖放
“源元素”触发 ondrag 拖放过程中
“源元素”触发 ondragend 结束拖放
“目标元素”触发 ondragenter 当被拖放的元素进入本元素时
“目标元素”触发 ondragover 当被拖放的元素正在本元素范围内移动时
“目标元素”触发 ondragleave 当被拖放的元素离开本元素时
“目标元素”触发 ondrop 当“源元素”释放到本元素时

一个完整的拖放事件过程如下图所示,我们可以轻松地使用上表所示的事件来处理复杂的拖放效果。

举例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        body {
            position: relative;
        }

        img {
            position: absolute;
            width: 200px;
            height: 200px;
        }
    </style>
    <script>
        window.onload = function () {
            const oImg = document.getElementsByTagName("img")[0];
            let offsetX, offsetY;
            //元素每次拖动开始时,记录它的坐标(偏移量)
            oImg.ondragstart = function (e) {
                offsetX = e.offsetX;
                offsetY = e.offsetY;
            };
            //元素拖动过程中,重新设置它的坐标(偏移量)
            oImg.ondrag = function (e) {
                if (e.pageX === 0 && e.pageY === 0) {
                    return;
                }
                oImg.style.left = (e.pageX - offsetX) + "px";
                oImg.style.top = (e.pageY - offsetY) + "px";
            }
        }
    </script>
</head>
<body>
<img src="test.png" alt="" draggable="true"/>
</body>
</html>

效果图:

说明:

当图片拖动开始时,会触发ondragstart事件,此时我们使用offsetX、offsetY这两个变量记录图片初始坐标。当图片被拖动时,会触发ondrag事件,此时我们重新设置图片的位置。其中,e.offsetX、e.offsetY分别表示鼠标相对于触发事件的对象的X坐标、Y坐标,e.pageX、e.pageY分别表示鼠标相对于当前窗口的X坐标、Y坐标。

2、dataTransfer对象

2.1、dataTransfer对象简介

在HTML5中,如果想要在元素拖放中实现数据传递,我们需要使用dataTransfer对象。dataTransfer对象主要用于在“源元素”与“目标元素”之间传递数据。dataTransfer对象有两个最重要的方法:setData()和getData()。在整个拖拽过程中,具体操作是这样的:开始拖放源元素时(ondragstart事件),调用setData()方法保存数据;然后在放入目标元素时(ondrop事件),调用getData()方法读取数据。

2.1.1、setData()方法

在拖放操作中,我们可以使用setData()方法保存数据。

语法:

setData(format, data);

参数format表示数据格式,常见的数据格式如下表所示:

数据格式 说明
text/plain 文本文字格式
text/html HTML代码格式
text/xml XML字符格式
text/url-list URL列表格式

举例:

source.ondragstart = function (e) {
    e.dataTransfer.setData("text/plain", e.target.id);
}

2.1.2、getData()方法

在拖放操作中,我们可以使用getData()方法读取数据。

语法:

getData(format);

参数format表示数据格式,数据格同2.1.1表格。

举例:

dest.ondrop = function (e) {
    e.dataTransfer.getData("text/plain");
}

2.2、dataTransfer对象应用

dataTransfer对象在元素拖拽的应用开发中使用非常广泛,下面举几个经典的实际案例进行说明:

2.2.1、举例1:元素拖动效果

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        ul {
            width: 120px;
            height: 120px;
            border: 1px solid silver;
        }
    </style>
    <script>
        window.onload = function () {
            const oList = document.getElementById("list");
            const oLi = oList.getElementsByTagName("li");
            const oBox = document.getElementById("box");
            //为每一个li(源元素)添加ondragstart事件
            for (let i = 0; i < oLi.length; i++) {
                oLi[i].ondragstart = function (e) {
                    e.dataTransfer.setData("text/plain", e.target.id);
                };
            }
            //调用event.preventDefault()方法来屏蔽元素的默认行为,否则drop事件不会被触发!
            oBox.ondragover = function (e) {
                e.preventDefault();
            };
            //为目标元素添加ondrop事件
            oBox.ondrop = function (e) {
                e.preventDefault();
                const id = e.dataTransfer.getData("text/plain");
                const obj = document.getElementById(id);
                oBox.appendChild(obj);
            };
        }
    </script>
</head>
<body>
<ul id="list">
    <li draggable="true" id="li1">HTML5</li>
    <li draggable="true" id="li2">CSS3</li>
    <li draggable="true" id="li3">JavaScript</li>
    <li draggable="true" id="li4">jQuery</li>
    <li draggable="true" id="li5">Vue</li>
</ul>
<ul id="box"></ul>
</body>
</html>

效果图:

分析说明:

for (let i = 0; i < oLi.length; i++) {
    oLi[i].ondragstart = function (e) {
        e.dataTransfer.setData("text/plain", e.target.id);
    };
}

首先,我们为每一个li元素添加ondragstart事件,e.dataTransfer表示获取dataTransfer对象,e.target.id表示获取当前事件的元素的id值。

oBox.ondragover = function (e) {
    e.preventDefault();
};

上面这段代码表示调用event.preventDefault()方法来屏蔽元素的默认行为。如果没有屏蔽掉,则drop事件不会被触发。

oBox.ondrop = function (e) {
    e.preventDefault();
    const id = e.dataTransfer.getData("text/plain");
    const obj = document.getElementById(id);
    oBox.appendChild(obj);
};

最后,我们为目标元素box添加ondrop事件,并且在ondrop事件中使用getData()方法获取元素的id值,从而使用DOM操作把li元素添加到box中。此外,e.preventDefault()也是用于屏蔽元素的默认行为,e.dataTransfer.getData(“text/plain”)表示调用dataTransfer对象的getData()方法获取数据。

2.2.2、举例2:垃圾箱效果

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        #bigBox {
            display: inline-block;
            width: 100px;
            height: 100px;
            background-color: green;
        }

        #smallBox {
            display: inline-block;
            width: 50px;
            height: 50px;
            background-color: gray;
        }
    </style>
    <script>
        window.onload = function () {
            const oBigBox = document.getElementById("bigBox");
            const oSmallBox = document.getElementById("smallBox");
            oSmallBox.ondragstart = function () {
            };
            oBigBox.ondragover = function (e) {
                e.preventDefault();
            };
            oBigBox.ondrop = function (e) {
                e.preventDefault();
                oSmallBox.parentNode.removeChild(oSmallBox);
            };
        }
    </script>
</head>
<body>
<div id="bigBox"></div>
<div id="smallBox" draggable="true"></div>
</body>
</html>

效果图:

分析说明:

oSmallBox.ondragstart = function () {};

首先,我们为smallBox元素添加ondragstart事件,由于这里ondragstart内部不需要做什么操作,所以可以删除该事件。

oBigBox.ondragover = function (e) {
    e.preventDefault();
};

上面这段代码表示调用event.preventDefault()方法来屏蔽元素的默认行为。如果没有屏蔽掉,则drop事件不会被触发。

oBigBox.ondrop = function (e) {
    e.preventDefault();
    oSmallBox.parentNode.removeChild(oSmallBox);
};

最后,我们为目标元素bigBox添加ondrop事件,并且在ondrop事件中通过smallBox的父节点删除当前的smallBox节点。最终效果就是当我们将smallBox元素拖动到bigBox元素中时,smallBox元素就会被删除。

从上面两个例子可以知道,想要实现拖拽效果,一般情况下我们需要操作3个事件:ondragstart、ondragover和ondrop。如果某一个事件不涉及什么操作,也可以不写。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。