实现从桌面拖拽到网页

过去我们想实现网页中的拖拽效果,基本上都是使用DOM事件模型中的mousedown、mousemove、mouseup的事件监听来模拟拖拽效果,为了实现实时的拖拽移动效果,还要不停地获取鼠标的坐标,还要不停的修改元素的位置,代码要堆很多,而且性能上也很不好(不停地修改元素位置会导致页面reflow,除非绝对定位),现在有了html5原生的Drag & Drop 拖拽事件,真的是方便了许多,用”事半功倍”来形容绝不为过。

Drag & Drop 包括以下事件

  • dragstart :要被拖拽的元素开始拖拽时触发,这个事件对象是被拖拽元素
  • dragenter :拖拽元素进入目标元素时触发,这个事件对象是目标元素
  • dragover :拖拽某元素在目标元素上移动时触发,这个事件对象是目标元素
  • dragleave :拖拽某元素离开目标元素时触发,这个事件对象是目标元素
  • dragend :在drop之后触发,就是拖拽完毕时触发,这个事件对象是被拖拽元素
  • drop :将被拖拽元素放在目标元素内时触发,这个事件对象是目标元素

完成一次成功页面内元素拖拽的行为事件过程应该是: dragstart –> dragenter –> dragover –> drop –> dragend

Drag & Drop 网页内的元素拖拽:

HTML5为元素新增了用于拖拽的属性 draggable ,这个属性决定了元素是否能被拖拽,如果draggable=”true”,则元素可被拖拽,否则只能选择元素的文本。

值得一提的是HTML5支持拖拽数据存储,使用 dataTransfer 接口,作用于元素的拖拽基础上,dataTransfer对象包含以下属性和方法:

  • dataTransfer.dropEffect [ = value ] :返回已选择的拖放效果,如果该操作效果与起初设置的effectAllowed效果不符,则拖拽操作失败。可以设置修改,包含这几个值: “none”, “copy”, “link” 和 “move”
  • dataTransfer.effectAllowed [ = value ] :返回允许执行的拖拽操作效果,可以设置修改,包含这些值: “none”, “copy”, “copyLink”, “copyMove”, “link”, “linkMove”, “move”, “all” 和 “uninitialized”
  • dataTransfer.types :返回在dragstart事件出发时为元素存储数据的格式,如果是外部文件的拖拽,则返回”files”
  • dataTransfer.clearData ( [ format ] ) :删除指定格式的数据,如果未指定格式,则删除当前元素的所有携带数据
  • dataTransfer.setData(format, data) :为元素添加指定数据
  • dataTransfer.getData(format) :返回指定数据,如果数据不存在,则返回空字符串
  • dataTransfer.files :如果是拖拽文件,则返回正在拖拽的文件列表FileList
  • dataTransfer.setDragImage(element, x, y) :制定拖拽元素时跟随鼠标移动的图片,x、y分别是相对于鼠标的坐标(据测试,Chrome暂不支持)
  • dataTransfer.addElement(element) :添加一起跟随拖拽的元素,如果你想让某个元素跟随被拖拽元素一同被拖拽,则使用此方法(据测试,Chrome暂不支持)

在dragstart事件触发时可以为被拖拽元素存储数据,就是使用上面说到的 dataTransfer.setData ,setData的数据格式一般有两种:”text/plain”(用于文本数据)和”text/uri-list”(用于url),你可以先为某个可拖拽元素设置微数据,然后为它设置draggable属性为true,之后在其dragstart事件触发时存储数据:

html部分:

XML/HTML Code 复制内容到剪贴板
  1. < div id = "dragMe" builddate = "2011-1-10" draggable = "true" > 拖拽我! </ div >
  2. < div id = "dropHere" > </ div >
  1. var oDragMe = document.getElementById( 'dragMe' );
  2. oDragMe.addEventListener( 'dragstart' , function (e) {
  3. e.dataTransfer.setData( 'text/plain' , e.target.getAttribute( 'builddate' ));
  4. }, false )

在拖拽结束的时候便可以获取相应元素的数据:

JavaScript Code 复制内容到剪贴板
  1. var oDropBox = document.getElementById( 'dropHere' );
  2. oDropBox .addEventListener( 'drop' , function (e) {
  3. tmpData = e.dataTransfer.getData( 'text/plain' );
  4. }, false )

创建拖拽事件监听的时候记得要把默认的行为事件去掉,毕竟浏览器是有默认拖拽行为的,尤其是dragover事件一定要使用e.preventDefault(),不然drop事件可能不会被触发:

JavaScript Code 复制内容到剪贴板
  1. oDropBox .addEventListener( 'dragover' , function (e) {
  2. e.stopPropagation();
  3. e.preventDefault();
  4. }, false )

上面讲的这些基本上就能完成页面内元素的拖拽操作了,下面我们来说说从本地拖拽图片到页面元素中用到的技术:

  1. // 异步读取方法
  2. void readAsArrayBuffer( in Blob blob);
  3. void readAsBinaryString( in Blob blob);
  4. void readAsText( in Blob blob, [Optional] in DOMString encoding);
  5. void readAsDataURL( in Blob blob);
  1. // 事件处理
  2. attribute Function onloadstart;
  3. attribute Function onprogress;
  4. attribute Function onload;
  5. attribute Function onabort;
  6. attribute Function onerror;
  7. attribute Function onloadend;

今天只说说关于拖拽本地文件到页面的几个相关FileReader属性和事件:

  • readAsDataURL方法 :参数为要读取的文件对象,将文件读取为DataUrl
  • onload事件 :当读取文件成功完成的时候触发此事件

在FileReader onload事件触发后,你可以通过 this.result 来获取读取的文件数据,如果是图片,将返回base64格式的图片数据。

JavaScript Code 复制内容到剪贴板
  1. //一定要在dragover事件中取消默认拖拽行为,不然drop事件会失效
  2. oDropBox.addEventListener( 'dragover' , function (e) {
  3. e.stopPropagation();
  4. e.preventDefault();
  5. }, false );
  6. oDropBox.addEventListener( 'drop' , handleDrop, false );
  7. function handleDrop(e) {
  8. e.stopPropagation();
  9. e.preventDefault();
  10. var fileList  = e.dataTransfer.files, //获取拖拽文件
  11. oImg = document.createElement( 'img' ),
  12. reader = new FileReader();
  13. reader.onload = function (e) {
  14. oImg.src = this .result;
  15. oDropBox.appendChild(oImg);
  16. }
  17. reader.readAsDataURL(fileList[0]); //这里只取拖拽的第一个,实际中你可以遍历处理file列表

OK,通过以上代码你就可以完成基本的本地图片拖拽到页面指定元素内的功能了。

实现从桌面拖拽到网页 过去我们想实现网页中的拖拽效果,基本上都是使用DOM事件模型中的mousedown、mousemove、mouseup的事件监听来模拟拖拽效果,为了实现实时的拖拽移动效果,还要不停地获取鼠标的坐标,还要不停的修改元素的位置,代码要堆很多,而且性能上也很不好(不停地修改元素位置会导致页面reflow,除非绝对定位),现在有了html5原生的Drag & Drop 拖拽事