灏天阁

元素拖放 Drag

· Yin灏

元素拖放简介

在 HTML5 之前,如果想要实现一个元素的拖放效果,我们一般需要结合该元素的 onmousedown、onmousemove、onmouseup 等多个事件来共同完成。这种方式代码量非常大,而且也仅限于在浏览器内的元素间拖放,不能实现跨应用拖放。

在 HTML5 中,我们只需要给元素添加一个 draggable 属性,然后设置该属性值为 true,就能实现元素的拖放。拖放,指的是“拖曳”和“释放”。在页面中进行一次拖放操作,我们必须先弄清楚两个元素:“源元素”和“目标元素”。“源元素”指的是被拖曳的那个元素,“目标元素”指的是源元素最终被释放到的那个元素。

如果仅给元素设置 draggable=“true”,则该元素只具备可拖曳的特点,并不能改变元素的位置。如果想要拖动改变元素的位置,我们还需要结合元素拖放触发的事件来操作。其中,拖放事件总共有 7 个

  • 源元素触发的事件
  • 目标元素触发的事件

一个完整的拖放事件过程如图:

举例:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
      * {
        margin: 0;
        padding: 0;
      }
      body {
        position: relative;
      }
      img {
        position: absolute;
      }
    </style>
    <script>
      window.onload = function () {
        var oImg = document.getElementsByTagName("img")[0];
        var 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="pic.png" alt="" draggable="true" />
  </body>
</htm

元素拖放

分析:

当图片拖动开始时,会触发 ondragstart 事件,此时我们使用 offsetX、offsetY 这两个变量记录图片初始坐标。当图片被拖动时,会触发 ondrag 事件,此时我们重新设置图片的位置。

其中,e.offsetX、e.offsetY 分别表示鼠标相对于触发事件的对象的 X 坐标、Y 坐标,e.pageX、e.pageY 分别表示鼠标相对于当前窗口的 X 坐标、Y 坐标。

dataTransfer对象

  1. dataTransfer 对象简介

在 HTML5 中,如果想要在元素拖放中实现数据传递,我们需要使用 dataTransfer 对象。dataTransfer 对象主要用于在“源元素”与“目标元素”之间传递数据。

dataTransfer对象有两个最重要的方法:setData() 和 getData()。在整个拖曳过程中,具体操作是这样的:开始拖放源元素时(ondragstart事件),调用 setData() 方法保存数据;然后在放入目标元素时(ondrop事件),调用 getData() 方法读取数据。

  • setData() 方法

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

setData(format, data);

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

举例:

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

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

getData(format);

参数format表示数据格式

举例:

dest.ondrop=function(e){
  e.dataTransfer.getData("text/plain");
};
  1. dataTransfer 对象应用

dataTransfer 对象在元素拖曳的应用开发中使用非常广泛,

举例:元素拖拽效果

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
      ul {
        width: 120px;
        height: 100px;
        border: 1px solid silver;
      }
    </style>
    <script>
      window.onload = function () {
        var oList = document.getElementById("list");
        var oLi = oList.getElementsByTagName("li");
        var oBox = document.getElementById("box");
        //为每一个li(源元素)添加ondragstart事件
        for (var 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();
          var id = e.dataTransfer.getData("text/plain");
          var obj = document.getElementById(id);
          oBox.appendChild(obj);
        };
      };
    </script>
  </head>
  <body>
    <ul id="list">
      <li draggable="true" id="li1">HTML</li>
      <li draggable="true" id="li2">CSS</li>
      <li draggable="true" id="li3">JavaScript</li>
      <li draggable="true" id="li4">jQuery</li>
      <li draggable="true" id="li5">Vue.js</li>
    </ul>
    <ul id="box"></ul>
  </body>
</html>

分析:

for (var 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();
  var id = e.dataTransfer.getData("text/plain");
  var obj = document.getElementById(id);
  oBox.appendChild(obj);
};

最后,我们为目标元素 oBox 添加 ondrop 事件,并且在 ondrop 事件中使用 getData() 方法获取元素的id值,从而使用 DOM 操作把 li 元素添加到 oBox 中。

此外,e.preventDefault() 也是用于屏蔽元素的默认行为,e.dataTransfer.getData(“text/plain”) 表示调用 dataTransfer 对象的 getData() 方法获取数据。

举例:垃圾箱效果

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
    <style type="text/css">
      #bigBox {
        display: inline-block;
        width: 100px;
        height: 100px;
        background-color: hotpink;
      }
      #smallBox {
        display: inline-block;
        width: 50px;
        height: 50px;
        background-color: lightskyblue;
      }
    </style>
    <script>
      window.onload = function () {
        var oBigBox = document.getElementById("bigBox");
        var 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>

分析:

当我们将 smallBox 元素拖动到 bigBox 元素中时,smallBox 元素就会被删除。

- Book Lists -