H5 拖放 - 学习

作者: 岁月静好_不负此生 | 来源:发表于2019-11-27 23:52 被阅读0次

前言

一个典型的drag操作是这样开始的:用户用鼠标选中一个可拖动的(draggable)元素,移动鼠标到一个可放置的(droppable)元素,然后释放鼠标。 在操作期间,会触发一些事件类型,有一些事件类型可能会被多次触发

第一部分 在拖动元素上

要使其他的 HTML 元素可拖动,必须做三件事:

  • 在你想要拖动的元素上,将 draggable 属性设置成 true
  • 为事件添加一个监听器 dragstart
  • 在上面定义的监听器中设置拖动数据

1.1 draggable: 可拖动属性

  • draggable: 全局属性, 是一个枚举类型, 而不是布尔类型. 这意味着必须显式指定值为 true 或者 false ,像 <label draggable>Example Label</label> 这样的简写是不允许的。正确的用法是` <label draggable="true">Example Label</label>
  • 默认情况下,只有已选中的文本、图片、链接可以拖动。对其它的元素来说,必须按拖动机制的顺序设置 ondragstart 事件才能正常工作
  • 属性 draggable 设置为 true,所以这个元素变成可拖动的。如果该属性被省略或被设置为 false,则该元素将不会被拖动,而是只选中文本。
  • 注意,当一个元素被设置成可拖动的时候, 文本或者其中的其他元素不能再以正常的方式(通过鼠标点击和拖动)被选择。用户必须按住 alt 键,用鼠标选择文本,或者使用键盘来代替。
    <!-- 
      拖动元素, 设置全局拖动属性   
     -->
    <div class="drop-item" draggable="true"></div>

1.2 ondragstart: 开始拖动事件

  • 当用户开始拖动时,会触发 dragstart 事件(此事件会冒泡),
  • 所有拖拽事件都有一个名为 dataTransfer的属性,它持有拖曳数据(dataTransfer 是一个 DataTransfer 对象)。
  • 一个web应用需要添加拖拽功能时,应当仅仅使用DragEvent(事件对象)和DataTransfer(事件对象中的属性)接口即

DataTransfer对象

这个对象可以从所有拖动事件 drag eventsdataTransfer属性上获取,但是不能单独创建。

详情见MDN资料

  • 属性:

    • dropEffect: 影响到拖动过程中浏览器显示的鼠标样式
  • 方法:

    • setData: 设置拖动数据
    /**
           * @name: 设置拖动元素的数据
           * @param {type: 数据MIME} 
           * @param {value: 数据值} 
           * @return: none
    */
    event.dataTransfer.setData(type, value);
    
    // =============== 示例 ==============
    /*
        * type类型: 
            application/x-bookmark: 自定义类型
            text/uri-list: URL
            text/plain: 文本
        * 您可以以多种格式提供数据, 每种格式可以提供一次, 如果您试图以相同的格式添加两次数据,那么新的数据将替换旧的数据。
        * 不能设置复杂类型数据, 此时可以通过反序列化解决
    */
    var dt = event.dataTransfer;
    dt.setData("application/x-bookmark", bookmarkString);
    dt.setData("text/uri-list", "http://www.mozilla.org");
    dt.setData("text/plain", "http://www.mozilla.org");
    
    • getData(): 获取设置的数据
    /**
             * @name: 获取通过setData()设置的数据
             * @param {type: 数据MIME} 
             * @return: none
    */
    event.dataTransfer.clearData(type);
    
    /*
      * 参数必填, 没有参数会直接报错
      * 当参数的 MIME 没有对应值时, 返回空字符串
    */
    event.dataTransfer.getData("text/plain");
    
    • clearData: 清除数据**
    /**
           * @name: 清除拖动元素的数据
           * @param {type?: 数据MIME} 
           * @return: none
    */
    event.dataTransfer.clearData(type);
    
    // ================ 示例 ==================
    /*
        * 如果没有参数调用此方法,或者格式为空 ,则将删除所有类型的数据。
        * 该方法只能在dragstart 事件的处理程序中使用,因为这是拖动操作的数据存储只能写入的时间。
        * 
    */
    event.dataTransfer.clearData("text/uri-list");
    
    • setDragImage(): 设置拖动反馈图像

    当一个拖动发生时,一个半透明的图像是由拖拽目标生成的("dragstart" 事件被触发的元素),并在拖动过程中跟踪鼠标指针。这个映像是自动创建的,所以你不需要自己创建它。但是,您仍然可以使用 setDragImage() 方法来自定义拖动反馈图像。

    /**
           * @name: 设置拖动反馈图像
           * @param {image: 图像的引用, 通常是图像元素, 也可以是画布(canvas) 或任何其他元素}
           * @param {xOffset: 相对于图片的横向偏移量}
           * @param {yOffset: 相对于图片的纵向偏移量}
           * @return: none
    */
    event.dataTransfer.setDragImage(image, xOffset, yOffset);
    
    // ============== 示例 ===========
    /*
        * 引用通常是一个图像元素,但它也可以是画布(canvas)或任何其他元素。
    */
    var canvas = 
    document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
    canvas.width = canvas.height = 50;
    
    var ctx = canvas.getContext("2d");
    ctx.lineWidth = 4;
    ctx.moveTo(0, 0);
    ctx.lineTo(50, 50);
    ctx.moveTo(0, 50);
    ctx.lineTo(50, 0);
    ctx.stroke();
    
    var dt = event.dataTransfer;
    dt.setData('text/plain', 'Data to Drag');
    dt.setDragImage(canvas, 25, 25);
    

第二部分 放置目标

web页面或应用程序的大多数区域都不是 drop 数据的有效位置。因此,这些事件的默认处理是不允许出现 drop。

如果您想要允许 drop,您必须通过取消事件来防止默认的处理, 在 dragover 事件中调用 preventDefault() 方法将表明在该位置允许 drop 。

1. dragover: 当元素或选中的文本被拖到一个可释放目标上时触发(每100毫秒触发一次)。

在 dragover 事件中调用 preventDefault() 方法, 但是这样的话, 会将所有拖动元素放置进来, 通常希望只在某些情况下调用 preventDefault() 方法, 这时可以通过检查拖放元素的 dataTransfer 的types属性(而使用ev.dataTransfer.getData("text/plain") 这种方式无用, 因为在dragover事件中无法获取到数据的)

  • types属性: 拖动操作中使用的数据格式数组。每种格式都是字符串类型。如果拖动操作不包含数据,则此数组列表将为空。如果拖动操作中包含任何文件,则其中一个类型将是Files。

    特别注意: 这是一个只读属性, 如果通过event.dataTransfer打印出来是查看不到数据的, 需要enent.dataTransfer.types直接查看数据

    // 可以通过判断 types 中存放的数据类型来判断是否是需要的拖动元素 (因为图片, 链接也是默认可以拖动的) -- form/item(可以自定义类型的)
        if ([...e.dataTransfer.types].includes("form/item")) {
          e.preventDefault();
        }
    

2. drop: 拖动元素放置的时候触发

处理放置效果, 在drop事件中处理, 在这个事件中可以调用event.dataTransfer.getData()来获取数据

注意每个处理程序调用 preventDefault() 来阻止对这个事件的其它处理过程(如触点事件或指针事件)

// 拖动第四步: 在拖动元素放置到 放置目标 , 执行一系列的操作
  // drop事件: 当元素或选中的文本在可释放目标上被释放时触发
  box.addEventListener("drop", function(e) {
    console.log(e.dataTransfer.getData("form/item"));
    e.preventDefault();
    this.innerText = e.dataTransfer.getData("form/item");
  });

第三部分 简单实例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        bottom: 0;
      }
      div {
        display: inline-block;
        margin-right: 100px;
      }
      .dorp {
        width: 100px;
        height: 100px;
        background: #000;
      }
      .box {
        width: 300px;
        height: 300px;
        border: 1px solid red;
      }
      .box2 {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <!-- 拖动第一步: 设置可拖动属性 -->
    <div class="dorp" draggable="true"></div>
    <div class="box">
      <div class="box2"></div>
    </div>
    <div class="dorp" draggable="true"></div>
  </body>
</html>
<script>
  let dorp = document.querySelector(".dorp");
  let box = document.querySelector(".box");
  // 拖动第二步: 开始拖动时, 设置拖动数据
  // dragstart事件: 当用户开始拖动一个元素或选中的文本时触发
  dorp.addEventListener("dragstart", e => {
    // 获取dateTransfer接口
    let dt = e.dataTransfer;
    // 设置拖动过程中数据 -- 可以自定义的
    dt.setData("form/item", "这可能是一个下拉框选项");
  });

  // 拖动第三步: 在放置目标上处理dragover事件 ==> 阻止默认事件(可以根据数据类型不同来判断是否可以放置)
  // dragover事件: 当元素或选中的文本被拖到一个可释放目标上时触发(每100毫秒触发一次)。
  box.addEventListener("dragover", e => {
    // 可以通过判断 types 中存放的数据类型来判断是否是需要的拖动元素 (因为图片, 链接也是默认可以拖动的)
    if ([...e.dataTransfer.types].includes("form/item")) {
      e.preventDefault();
    }
  });
  // 拖动第四步: 在拖动元素放置到 放置目标 , 执行一系列的操作
  // drop事件: 当元素或选中的文本在可释放目标上被释放时触发
  box.addEventListener("drop", function(e) {
    console.log(e.dataTransfer.getData("form/item"));
    e.preventDefault();
    this.innerText = e.dataTransfer.getData("form/item");
  });
</script>

最后

只是简单学习了一下H5的拖放过程, 没有深入的细究, 还有好多事件 和 属性在一定的场景下有作用的

参考资料

相关文章

  • H5 拖放 - 学习

    前言 一个典型的drag操作是这样开始的:用户用鼠标选中一个可拖动的(draggable)元素,移动鼠标到一个可放...

  • H5拖放异步文件上传之二——上传进度监听

      上一篇《H5拖放+FormData接口+NodeJS,完整异步文件上传(一)》,我们走通了拖放文件上传的整个流...

  • HTML5拖放

    拖放 拖放是一种常见的特效---将某个对象拖到某个位置。在H5中,任何元素都都能拖放。 实例: 亲自试一试 实例解...

  • 原生的 HTML 5 拖拽与JavaScript File AP

    W3C中关于H5拖拽(拖放)的介绍 拖放(Drag 和 drop)是 HTML5 标准的组成部分拖放是一种常见的特...

  • H5拖放

    H5拖放 提到拖拽,我们都很熟悉,那么拖放呢?一字之差,代表的意义是不一样的,拖拽就是拉着走,拖放就是有拖,有放,...

  • h5图片拖放功能

    首先什么是html5拖放? 答:html5拖放是h5标准的组成部分 拖动开始: ondrapstart:调用一个函...

  • H5 拖放

    创建拖放对象 draggable 通过draggable告诉浏览器哪些元素需要实现拖拽功能。有三个可选值: tr...

  • H5 拖放事件详解

    拖放事件 H5的拖放事件提供了多个接口: 1、drag:当元素或者选中的文本被拖动时触发(每几百毫秒触发一次),应...

  • h5资源拖放

    什么是h5资源拖放呢? 答:就是将本地的图片直接拖放在屏幕上显示。 首先在页面中布局一块放置要被拖入的框框 对这个...

  • H5 元素拖放

    今天分享一个元素拖放的案例,注意:这个是H5新增的; 先放图一张: 代码:(一些API和细节都在代码注释里了)

网友评论

    本文标题:H5 拖放 - 学习

    本文链接:https://www.haomeiwen.com/subject/zlqvwctx.html