HTML5 drag & drop 拖拽与拖放简介

这篇文章发布于 2011年02月9日,星期三,20:58,归类于 JS API。 阅读 448496 次, 今日 6 次 70 条评论

 

一、前面的话

HTML5提供专门的拖拽与拖放的API,以后实现这类效果就不必乱折腾了。但是,考虑到Opera浏览器似乎对此不感冒,在通用性上有待商榷,所以这里也就简单说一说。

二、相关重点

  1. DataTransfer 对象:退拽对象用来传递的媒介,使用一般为Event.dataTransfer。
  2. draggable 属性:就是标签元素要设置draggable=true,否则不会有效果,例如:
    <div title="拖拽我" draggable="true">列表1</div>
  3. ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上
  4. ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此事件作用在目标元素上
  5. ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
  6. ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上
  7. ondragend 事件:当拖拽完成后触发的事件,此事件作用在被拖曳元素上
  8. Event.preventDefault() 方法:阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。
  9. Event.effectAllowed 属性:就是拖拽的效果。

三、相关实例

为了便于理解上面的粗体的事件啊对象啊什么的,做了个很简单的demo页面。

您可以狠狠地点击这里:HTML5 drag & drop删除元素demo

此demo实现的效果是把右侧的列表拖动到左侧的写着果敢的“垃圾箱”三个字的div层上,此列表元素就会从这个星球上消失。如下截图连环画所示:
列表元素拖拽删除截图之鼠标经过 张鑫旭-鑫空间-鑫生活
html5 drag & drop ondragstart截图 张鑫旭-鑫空间-鑫生活
html5 drag & drop 拖拽与拖放经过目标元素截图 张鑫旭-鑫空间-鑫生活
HTML5 drag drop demo ondrop截图 张鑫旭-鑫空间-鑫生活

源代码展示
其中HTML结构如下:

<div class="dustbin"><br />垃<br />圾<br />箱</div>
<div class="dragbox">
    <div class="draglist" title="拖拽我" draggable="true">列表1</div>
    <div class="draglist" title="拖拽我" draggable="true">列表2</div>
    <div class="draglist" title="拖拽我" draggable="true">列表3</div>
    <div class="draglist" title="拖拽我" draggable="true">列表4</div>
    <div class="draglist" title="拖拽我" draggable="true">列表5</div>
    <div class="draglist" title="拖拽我" draggable="true">列表6</div>
</div>
<div class="dragremind"></div>

JS代码如下:

var $ = function(selector) {
    /*简单的选择器方法*/
    ...
};

var eleDustbin = $(".dustbin")[0], eleDrags = $(".draglist"), lDrags = eleDrags.length, eleRemind = $(".dragremind")[0], eleDrag = null;
for (var i=0; i<lDrags; i+=1) {
    eleDrags[i].onselectstart = function() {
        return false;
    };
    eleDrags[i].ondragstart = function(ev) {
        /*拖拽开始*/
        //拖拽效果
        ev.dataTransfer.effectAllowed = "move";
        ev.dataTransfer.setData("text", ev.target.innerHTML);
        ev.dataTransfer.setDragImage(ev.target, 0, 0);
        eleDrag = ev.target;
        return true;
    };
    eleDrags[i].ondragend = function(ev) {
        /*拖拽结束*/
        ev.dataTransfer.clearData("text");
        eleDrag = null;
        return false
    };
}
eleDustbin.ondragover = function(ev) {
    /*拖拽元素在目标元素头上移动的时候*/
    ev.preventDefault();
    return true;
};

eleDustbin.ondragenter = function(ev) {
    /*拖拽元素进入目标元素头上的时候*/
    this.style.color = "#ffffff";
    return true;
};
eleDustbin.ondrop = function(ev) {
    /*拖拽元素进入目标元素头上,同时鼠标松开的时候*/
    if (eleDrag) {
        eleRemind.innerHTML = '<strong>"' + eleDrag.innerHTML + '"</strong>被扔进了垃圾箱';
        eleDrag.parentNode.removeChild(eleDrag);
    }
    this.style.color = "#000000";
    return false;
};

四、匆匆结语

今天是年后第一天上班,没有多少想折腾的心情,所以,一些啰哩吧嗦的话就省了。虽然是HTML5的东西,但是,根据findmebyip中显示的浏览器支持情况来看,IE6~IE8都是有drag & drop API的(见下截图)。
IE6~IE8也是有drag&drop API的 张鑫旭-鑫空间-鑫生活

根据自己的简单的测试,低版本的IE浏览器确实支持诸如ondragstart事件,但是会报不认识dataTransfer的错误。可见IE在细节的处理上与现代浏览器有些不同。但是,目前自己没有这么多精气神把IE下的拖拽也折腾出来,故请原谅目前demo在IE下是纹丝不动,没有效果也不报错的。回头有功夫,一定会把IE相关的些东西补上。

感谢阅读。文中要是有表述不准确的地方,欢迎指正。

(本篇完)

分享到:


发表评论(目前70 条评论)

  1. 小菜鸡说道:

    大佬,拖动的时候,draggable=“true”, @dragstart=”dragStartFn”,为什么点击后不触发start?拖动元素层级也在最上层,不解

  2. asdfq说道:

    关键是触摸屏难拖动。

  3. QQ 浏览器的兼容性问题说道:

    发现在 QQ 浏览器里不支持 drop 事件,旭哥有什么好的建议吗,谢谢 ~

  4. 李甜甜说道:

    在拖拽的过程中出现的禁用标志可以修改吗?可以修改成一个手势的标志吗?

  5. 全林聪说道:

    膜拜

  6. 王秀锋说道:

    大神,ondragleave 呢?
    刚遇到一个问题,vue框架
    ondragleave 会再dragover的时候触发,
    dragEvent 的offsetx,y 均在父盒子里面,
    明明写的 ”The dragleave event is fired when a dragged element or text selection leaves a valid drop target.“
    搞不懂为什么,望大神指教一二。

  7. 曹言歌说道:

    为什么手势无法拖放

  8. PLAxiaoxin说道:

    旭哥 看了你很多的技术文章 受益匪浅 ; 今天来才发现你出书了 必须得买啊

  9. harmsworth说道:

    我也买了《CSS世界》,期待书!

  10. harmsworth说道:

    大神,谷歌、火狐要把Http网站标记为不安全了

  11. demo说道:

    如果拖动的div下面有子节点,则在火狐浏览器无法拖动。子节点倒是能拖,怎么破?而且拖的时候松开就弹出新窗口,并没有用到setdata

  12. square说道:

    有个问题,在windows下拖动会产生鼠标变成禁止图标的样式,在mac下是没问题的,这个有解决的办法吗。。

  13. 双鱼小海豚说道:

    大神,拖拽后有什么方法刷新不改变状态呀?

  14. 说道:

    如何兼容移动端

  15. cocokeder说道:

    大神你好。我想请问一下我如何在drag过程中修改鼠标指针的样式?这个问题我查了好多地方大多用jqueryUI解决的。用的不是原生的drag事件。而我在项目里用的是原生的。而且用的是vue、

  16. 晴天说道:

    有个小bug。就是当被拖曳元素进入目标元素后,又出来,然后,目标元素上的颜色不会恢复。

  17. 大西瓜说道:

    大神,ie的问题啥时候能补充啊?

  18. 陆吾说道:

    chrome 53.0.2785.143 m 不能拖拽…

  19. boss说道:

    opera已经可以支持了

  20. 萱草说道:

    看完博主的这篇文章,自己操作了两遍,查看了很多资料,可能网上这方面的文章不是很有深度,没有找到自己满意的答案。一个是为什么每个事件后面都要加true,或者false;
    第二是‘ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。‘这句话,我也通过代码证明了确实是需要阻止默认行为的,但是为什么呢?

    • wac说道:

      ondragover执行preventDefault(),是因为默认情况下是无法将数据、元素放到其他元素中的,如果需要允许,就要阻止默认处理;

      • harmsworth说道:

        /*拖拽元素在目标元素头上移动的时候*/
        eleDustbin.ondragover = function (ev) {
        return false;
        };
        直接阻止默认行为

  21. 这个bug有bug说道:

    学习了,多谢博主

  22. 火狐打开新标签说道:

    drag后打开新标签,怎么解决

  23. 秀气学生说道:

    www_itcast_cn/news/20160520/1713344905.shtml
    刚刚看到这个网站上也有,觉得很奇怪

  24. awan说道:

    在拖拽的时候出现的两个层.一个层消失,另一个在可视区域外部,但是鼠标到达要拖拽的地方,位置是正确的,想问下,让消失的出现,并跟随鼠标的位置移动,怎么设置

  25. aSha说道:

    在 dragenter 与 dragover 事件中 return false 或者调用 event.preventDefault()(tips:因为拖放目标要通过取消事件来告知浏览器它对放置感兴趣)就可以在 IE , edge 等浏览器中拖放了

  26. 溪杨说道:

    有什么办法能改变拖放效果呢?浏览器原生的有点生硬,拖放的元素还会在原来的位置上,随着鼠标移动会更自然吧,被拖放到上面的元素似乎也不能挪动。

  27. 说道:

    测试了一下,<ie10以下都不支持这个功能。

  28. Lee说道:

    火狐下会新开一个窗口是什么情况,其他还可以

  29. H5 初学者说道:

    我想说 您的这篇文章 我是真的没看懂,,我想 对我来说 这JS代码的学习量比较大,,,我更想知道 一个最简单的拖拽是怎么实现的。

  30. 大兵说道:

    有一个问题,就是拖拽到垃圾桶但不放鼠标,这是垃圾桶颜色会变,如果这个时候我拖出垃圾桶,垃圾桶颜色不会reset
    因为没有类似dragleave事件

  31. d说道:

    chrome 39,安装了 超级拖曳 1.9.0.3 拓展程序插件,导致demo演示有问题。2015-5-21 14:09:20

  32. 陶留军说道:

    请问对移动设备的drag事件有研究吗?我测试了一些代码,发现drag在移动设备上并不能好好工作。所以尝试了 touch,但发现touch又不支持 touchenter,touchleave事件,所以我不能捕获目标对象。即便在touchmove中,我也只能捕获拖拽对象,不能捕获目标对象。 如果通过touch点的坐标,遍历dom来获取目标对象,应该是个得不偿失的高发代码。 请指教至EMAIL

  33. 鸳鸯汽水说道:

    你好,我遇到一个问题,想请教一下,我想用drag事件做一个产品图360全景功能,但是我不想有浏览器图片被拖放的事件发生,当我在ondragstart事件当中使用event.preventDefault()方法时,ondragover,也一并不产生效果了,请问有没有别的方法可以解决?

  34. 结局 怎么写说道:

    这个好像不好

  35. yala说道:

    setDragImage 这个函数在chrom和firefox、safari下不起做用,只有在opera下才有图片显示出来。。。

  36. 少年说道:

    楼主:我现在在用drag&drop做一个上传图片的功能。页面初始话时我默认的设置了一个拖拽区域。还有个添加新拖拽区域的按钮。如果拖动图片到默认的拖拽区时是可以上传成功的。但是我添加新的拖拽区域后,拖拽总是选中最后一拖拽区来上传图片。(我用的是从桌面直接拉文件,不是在页面上拉)。貌似没办法监听到拖动的位置。

  37. HTML5新手,希望多交流哦。

  38. 用C#思想理解HTML5拖、放:http://www.deepleo.com/archives/1386
    一点拙见,博主换链接吗?

  39. sfd说道:

    这个属性android或者iphone支持吗??

  40. kathy说道:

    您好,我想问一下,拖动的时候,会有两个层,一个是半透明的层,一个是实际的层,那个半透明的层是做什么的,怎么去掉呢

  41. infengr说道:

    你好,请问当ondrop时,我想要div框就停在那个地方,应该怎么做呢,谢谢

  42. maoxx说道:

    非常支持。
    今天照着写了一遍,发现drag事件在firefox上可以实现,但是在chrome上就实现不了了。
    我所用的chrome浏览器是15.0.874.106 m的。
    非常奇怪。

  43. 无聊人士说道:

    楼主你好,最近在实现一个网页IM,对话框的移动利用了drag属性,HTML结构为
    收到的消息
    实际过程中发现,设置a的draggable=true后,b中的文字无法进行选中操作了,只会触发a的drag事件,请求楼主帮忙检查下,谢谢了

  44. BlackGlory说道:

    这个例子只在Firefox中可以正常运行

  45. leavingme说道:

    写了个支持IE6+的Demo
    http://leavingme.net/cnblogs/draganddrop/systemdemo.html

    不知道您文章里所说的“但是会报不认识dataTransfer的错误”是咋回事,我好想没有遇到。

  46. 卵石说道:

    很好!支持……
    博主,ie6貌似不可以

  47. 山大芋说道:

    问张老师几个问题:
    1.effectAllowed 属性具体是什么效果?我加不加那句没有看出效果上有什么差别啊?
    2.setDragImage 函数是做什么用的呢?去掉似乎也无大碍。
    3.每个函数底部的return true和return false有什么讲究吗?
    4.在firefox下,ev.dataTransfer.clearData(“text”) 会抛出Modifications are not allowed for this document错误,不明原因。
    可能一些问题问得有点笨,望勿见笑啊。

  48. 夏雨说道:

    有了这个功能,页面可以做的更加智能化

  49. 说道:

    好。。支持一下