浏览器中的拖放API

简介:

1. 概述

新式浏览器中提供了一套处理拖放( Drag and Drop)行为的机制,主要是通过事件触发来响应行为,相应的数据则在事件对象中传递。使用这套机制,可以很容易地实现节点间的拖放行为定义,以及,浏览与系统中的其它应用程序的交互(比如文件的拖放)。

简单来说,这套机制中有如下的概念:

  • 触发节点 , “拖什么” 。
  • 目标节点 , “拖到哪里” 。
  • 数据 , 拖的是节点,但是承载的数据是什么。

这里,之所以把 数据 单独设计出来,是因为 触发节点 和 目标节点 它们本身是分离的,对应的事件也是独立的,这就是说,当你在处理 目标节点 的事件时,你是不能直接拿到 触发节点 的,但是显然,在流程上,在处理 目标节点 时一般又是需要知道 “从何而来” 的答案,于是,解决办案就变成了使用事件对象来传递具体的数据属性了 -- 触发节点 在对象属性中设置的值, 目标节点 可以获取到。

$('#source').on('dragstart', function(eventObj){
    eventObj.originalEvent.dataTransfer.setData('text/plain', 'I am source');
});

$('#target').on('dragenter', function(eventObj){
    var s = eventObj.originalEvent.dataTransfer.getData('text/plain');
    console.log('welcome, ' + s);
});

上面代码中的 dataTransfer 只在原生的事件对象中有,所以如果使用 jQuery 的话,要先从它封装的事件中取到 originalEvent ,再作操作。

2. 使用方法

上面已经简单介绍了三个基本的概念,在使用这套机制时,要作的事,就是绑定事件,传递数据而已,从上到下按顺序,一般的流程如下:

触发节点 dataTransfer 目标节点
dragstart 事件
setData(type, value)
drag 事件
dragenter 事件
dragover 事件 (1)
dragleave 事件
drop 事件 (2)
getData(type)
dragend 事件

上面有两点需要说明一下:

  • (1) , 这里处理事件时,如果确定是符合自己期望的东西被拖过来了,则需要显式调用事件的 preventDefault() 方法,否则后面的 drop 事件不会触发。
  • (2) , 这里处理事件时,最后也要显式调用 preventDefault() 方法,否则很可能触发浏览器对于拖放的默认行为,造成奇怪的结果。

3. 其它细节,伴随图片

伴随鼠标拖行的图片效果,是可以自定义的。在 firefox 上,可以直接给一个 canvas 对象,但是 chrome 中不行。不过,我们总可以把 canvas 直接转换成 image :

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 img = document.createElement("img");
img.src = canvas.toDataURL();

$('#source').on('dragstart', function(eventObj){
    eventObj.originalEvent.dataTransfer.setDragImage(img, 25, 25);
});

4. 其它细节,目标效果

按照这套机制设计的初衷,对于“效果”,本身是有单独支持的,即,对于一个拖发行为,你可以定义它是 “复制”,“移动”,“创建联系” 这三个中的哪一个,从而,在目标节点上,光标的视觉效果会有所不同,比如对于 “复制” ,会有一个“加号”。

但是,除了一个光标的样式,这东西好像没什么用:

$('#source').on('dragstart', function(eventObj){
    eventObj.originalEvent.dataTransfer.effectAllowed = 'copy';
});


$('.target').on('dragenter', function(eventObj){
    eventObj.originalEvent.dataTransfer.dropEffect = 'copy';
});

5. 代码示例

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>拖放效果</title>
</head>
<script type="text/javascript" src="jquery-2.1.4.js"></script>

<style type="text/css">
  #source { width: 100px; height: 100px; background-color: red; }
  .target { width: 200px; height: 100px; background-color: white; border: 1px solid black; }
</style>

<body>
  <div id="source" draggable="true"></div>
  <div class="target"></div>
  <div class="target"></div>


  <script type="text/javascript">
    $(function(){
    
      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 img = document.createElement("img");
      img.src = canvas.toDataURL();

      $('#source').on('dragstart', function(eventObj){
        eventObj.originalEvent.dataTransfer.setData('text/plain', (new Date()).valueOf());
        eventObj.originalEvent.dataTransfer.setDragImage(img, 25, 25);
        eventObj.originalEvent.dataTransfer.effectAllowed = 'copy';
      });

      $('#source').on('dragend', function(eventObj){
        console.log('end');
      });


      $('#source').on('drag', function(eventObj){
        //console.log('process');
      });

      $('.target').on('dragenter', function(eventObj){
        eventObj.originalEvent.dataTransfer.dropEffect = 'copy';
        console.log('enter');
      });

      $('.target').on('dragleave', function(eventObj){
        console.log('leave');
      });

      $('.target').on('dragover', function(eventObj){
        console.log('over');
        eventObj.preventDefault();
      });

      $('.target').on('drop', function(eventObj){
        var s = eventObj.originalEvent.dataTransfer.getData('text/plain');
        console.log('drop');
        console.log(s);
        eventObj.preventDefault();
        $(eventObj.target).text(s);
      });

    });
  </script>

</body>
</html>

6. 参考资料

目录
相关文章
|
3月前
|
JavaScript 前端开发 API
探索前端BOM API:解锁浏览器的潜力
探索前端BOM API:解锁浏览器的潜力
44 0
|
3月前
|
API Windows
介绍一款API浏览器--Dash
介绍一款API浏览器--Dash
33 0
|
4月前
|
Web App开发 前端开发 安全
File System Access API 让浏览器拥有操作本地文件的能力
File System Access API 让浏览器拥有操作本地文件的能力
89 0
|
4月前
|
JavaScript 前端开发 API
探索前端BOM API:解锁浏览器的潜力
探索前端BOM API:解锁浏览器的潜力
42 1
|
7月前
|
Web App开发 JavaScript 前端开发
在 SAP UI5 应用中使用浏览器原生的 Fetch API 发起网络请求试读版
在 SAP UI5 应用中使用浏览器原生的 Fetch API 发起网络请求试读版
35 0
|
8月前
|
API 数据安全/隐私保护 虚拟化
虚拟化——浏览器调用ovirt的api接口时,登录名和密码应该填什么?
虚拟化——浏览器调用ovirt的api接口时,登录名和密码应该填什么?
|
JavaScript 前端开发 API
重学前端 38 # 浏览器 API
重学前端 38 # 浏览器 API
99 0
|
移动开发 前端开发 JavaScript
Selenium WebDriver API 学习笔记(三):浏览器控制
Selenium WebDriver API 学习笔记(三):浏览器控制
116 0
|
测试技术 API Python
Selenium WebDriver API 学习笔记(二):浏览器控制
Selenium WebDriver API 学习笔记(二):浏览器控制
110 0
|
移动开发 JavaScript 前端开发
HTML的笔记及展示(1)(锚点、a元素添加超链接href、img元素、iframe元素、HTML5新增的拖放API)
HTML的笔记及展示(1)(锚点、a元素添加超链接href、img元素、iframe元素、HTML5新增的拖放API)
109 0
HTML的笔记及展示(1)(锚点、a元素添加超链接href、img元素、iframe元素、HTML5新增的拖放API)