onDrag & onDrop 使用dataTransfer传输数据时IE/chrome兼容问题

起因

前不久,有个需求要往地图上拖放添加设备图标,自然想到的就是ondragstart 、ondrop、ondragover,中间涉及传递拖曳设备的id、name等信息,这时就需要dataTransfer。所以就正常的开始撸:

function dragstart(event) {
    var itemData ={id:1,name:"demo"};
    event.dataTransfer.setData("data", JSON.stringify(itemData));
}

function allowDrop(event) {
    event.preventDefault();
}

function drop(event) {
    event.preventDefault();
    console.log(event.dataTransfer.getData("data")); 
    // TODO
}

<div id="div_drag" draggable="true" ondragstart="dragstart(event);">可拖曳元素</div>
<div id="div_drop" ondrop="drop(event)" ondragover="allowDrop(event)">拖曳放置区</div>

然后兴冲冲在Chrome下试了试拖曳,效果挺不错,是想要的结果。

{"id":1,"name":"demo"}

然而,当我打开IE浏览器(特别说明下,我这个是IE11,虽说兼容IE很痛苦,但好歹我们只需要考虑IE11,这样想来也算一种“幸福”吧)时,悲剧开始:

SCRIPT65535: 意外地调用了方法或属性访问。
Unknown script code (3) (4,5)

嗯???有问题,通过断点,找到问题所在:

event.dataTransfer.setData("data", JSON.stringify(itemData));

我知道的dataTransfer.setData只能传递string类似数据,所以已经做了序列化处理,那么问题很有可能出在"text/plain"身上。

ev.dataTransfer.setData("text/plain", ev.target.id);

探寻

不由地,翻开MSDN,找到如下一些介绍:

定义拖动数据
应用程序可以在拖动操作中包含任意数量的数据项。每个数据项都是一个 string 类型,典型的MIME类型,如:text/html
每个 drag event 都有一个dataTransfer 属性保保存事件的数据。这个属性( DataTransfer 对象)也有管理拖动数据的方法。setData() 方法添加一个项目的拖拽数据,如下面的示例代码所示:

function dragstart_handler(ev) {
  // 添加拖拽数据
  ev.dataTransfer.setData("text/plain", ev.target.id);
  ev.dataTransfer.setData("text/html", "<p>Example paragraph</p>");
  ev.dataTransfer.setData("text/uri-list", "http://developer.mozilla.org");
}

注:在旧代码中,可能会使用 text/unicode 或者 Text 类型, 这两个与 text/plain是一样的,并且应该被替换用于存储和提取数据。

查看推荐拖动类型了解可拖拽的通用数据类型(如文本,HTML,链接和文件),移步拖动数据获取更多有关拖动数据的信息

DataTransfer.setData() 方法用来设置拖放操作的drag data到指定的数据和类型。
如果给定类型的数据不存在,则将其添加到拖动数据存储的末尾,使得 types 列表中的最后一个项目将是新类型。
如果给定类型的数据已经存在,现有数据将被替换为相同的位置。也就是说,替换相同类型的数据时 types列表的顺序不会更改。
示例数据类型为:"text/plain" 和 "text/uri-list".

DataTransfer.types 是只读属性。它返回一个我们在dragstart事件中设置的拖动数据格式(如 字符串) 的数组。 格式顺序与拖动操作中包含的数据顺序相同。
这些格式是指定数据类型或格式的Unicode字符串,通常由MIME类型给出。 一些非MIME类型的值是由于历史遗留原因(例如“text”)而特殊设置的。

由上可以看出,HTML拖放支持拖动各种类型的数据,包括纯文本,URL,HTML代码,文件等。

恰巧IE就属于历史遗留问题,那么IE下“data”=>"text",会如何?赶紧试下,还不错,正常拖曳获取到值。

然后此时Chrome/Firefox又失效。看来现代浏览器还是比较遵循规范的,也就是DOMString (一个UTF-16字符串。由于JavaScript已经使用了这样的字符串,所以DOMString 直接映射到 一个String。)

故,不得不检测一下当前浏览器类型,针对IE设置不同string,例如:

 if (
      navigator.userAgent.indexOf('Trident') > -1 &&
      navigator.userAgent.indexOf('rv:11.0') > -1
    ) {
      data = JSON.parse(ev.dataTransfer.getData('text'));
    } else {
      data = JSON.parse(ev.dataTransfer.getData('data'));
    }

至于为什么不能像MSDN例子中一样,使用"text/plain",比如

ev.dataTransfer.setData("text/plain", ev.target.id);
data = JSON.parse(ev.dataTransfer.getData('text/plain'));

实际效果是不可以,网上有博客介绍:

Firefox在其第5个版本之前不能正确地将“URL”和“text”映射为“text/uri-list”和“text/plain”。但是却能把“Text”映射为“text/plain”。为了更好地在跨浏览器的情况下从dataTransfer对象取得数据,最好在取得URL数据时检测两个值,而在取得文本数据时使用“text”

然而实际(非demo网页,而是真实项目中)测试结果:

字符串 IE Chrome Firefox
“text” × ×
“data”(非text字符串) ×

看来,各大浏览器具体能不能映射,以及如何映射还真是各抒己见。不过主要开始IE的区别,故采用上面的方式,针对性的传值。

总结:

虽然问题已经解决,但是实际上对于其内部原理,自己还是懵懵懂懂,比如为什么使用普通demo页测试时,IE、Chrome、Firefox都可以正常使用“text”,而真实项目却出现上诉表格中的结果?目前来讲,其中原理还是需要深入探寻。

通过这次事件,也给我留下一点思考:我们真的知道我们在用什么吗?是仅仅满足能解决问题就OK,还是想去深入理解其内部实现原理。看来自己的前端之路确实还很漫长。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容

  •   HTML5 规范了很多新 HTML 标记。为了配合这些标记的变化,HTML5 规范也用显著篇幅定义了很多 Ja...
    霜天晓阅读 706评论 0 1
  • 文件API FileList对象与file对象 FileList对象表示用户选择的文件列表。在HTML4中,fil...
    oWSQo阅读 2,090评论 1 2
  • 一、 跨文档消息传递 跨文档消息传送(cross-document messaging),有时候简称为XDM,指的...
    Upcccz阅读 232评论 0 2
  • 接上 关于HTML/HTML5(一)http://www.jianshu.com/p/33fc7840c079 学...
    Amyyy_阅读 787评论 0 4
  • 一.line-height有什么作用? line-height是用于设置行高。并且在CSS中,有最底层的inlin...
    块垒阅读 393评论 0 0