浏览器中的拖放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. 参考资料

目录
相关文章
|
4月前
|
自然语言处理 API 数据处理
惊了!浏览器居然自带语音API和流处理API!
惊了!浏览器居然自带语音API和流处理API!
54 0
|
4月前
|
存储 移动开发 编解码
一文读懂Web Codecs API:浏览器背后的媒体魔术师
一文读懂Web Codecs API:浏览器背后的媒体魔术师
43 0
|
7月前
|
移动开发 API UED
【专栏:HTML进阶篇】HTML5拖放API与触摸事件
【4月更文挑战第30天】HTML5的拖放API和触摸事件增强了网页交互设计,使开发者能创建动态响应式界面。拖放API通过设定元素的`draggable`属性、监听拖动和放置事件以及处理`DataTransfer`对象实现。触摸事件如`touchstart`、`touchmove`、`touchend`则让触控设备操作更流畅。开发者需注意事件对象、多点触控处理和防止默认行为。结合两者,可创建图片排序、手势识别等交互功能,但也需面对浏览器兼容性和复杂逻辑挑战。利用HTML5这些工具,能提升用户体验,推动网页交互设计创新。
98 0
|
7月前
|
JavaScript 前端开发 API
探索前端BOM API:解锁浏览器的潜力
探索前端BOM API:解锁浏览器的潜力
134 0
|
7月前
|
API Windows
介绍一款API浏览器--Dash
介绍一款API浏览器--Dash
104 0
|
JavaScript 前端开发 API
探索前端BOM API:解锁浏览器的潜力
探索前端BOM API:解锁浏览器的潜力
86 1
|
7月前
|
Web App开发 前端开发 安全
File System Access API 让浏览器拥有操作本地文件的能力
File System Access API 让浏览器拥有操作本地文件的能力
211 0
|
API 数据安全/隐私保护 虚拟化
虚拟化——浏览器调用ovirt的api接口时,登录名和密码应该填什么?
虚拟化——浏览器调用ovirt的api接口时,登录名和密码应该填什么?
|
JavaScript 前端开发 API
重学前端 38 # 浏览器 API
重学前端 38 # 浏览器 API
137 0
|
移动开发 前端开发 JavaScript
Selenium WebDriver API 学习笔记(三):浏览器控制
Selenium WebDriver API 学习笔记(三):浏览器控制
154 0