拖放事件(drop events)在Firefox上运行会出现的问题
可能会有人觉得我废话特别多,我就在开头写一个简单粗暴的版本:
在Firefox中ondrop事件会触发Firefox自带的拖拽搜索功能,在ondrop事件触发执行时触发的函数中加上这两条:
1 /* 禁止冒泡行为 */ 2 event.stopPropagation(); 3 /* 禁止默认行为 */ 4 event.preventDefault();
这个时候Firefox拖拽的时候就不会弹出搜索页面了。
下面是废话特多的我的解决过程
在学习拖放事件的时候,我看的教程是用下面的一个例子去介绍这些事件的:
有两个<div>区域,其中一个<div>区域中有一个<p>元素,我们可以拖动<p>元素放到另一个<div>区域中,并且在控制台中会在刚开始拖动元素和元素拖动到指定区域的时候在控制台打印一句话。
效果像下面这样:
上面这张图是在Chrome中运行的效果,看起来是没啥问题是吧,但是在Firefox中却出了点问题:
没错在Firefox中,它会使用百度搜索我拖拽元素的id(我这个<p>元素的id="p1")。
不懂得事儿先去请教百度!在百度上一搜,原来大家都遇到过这个问题。
这一切的罪魁祸首原因是Firefox中的扩展组件中的有一个“拖拽手势”的功能,你可以选中一部分文字,拖拽它它就会使用设置好的搜索引擎去搜索你选中的内容,拖拽图片它就会在新标签打开这张图片。
我们可以在Firefox右上角的菜单中找到附加组件管理器,打开(或者按下Ctrl+Shift+A打开附加组件管理器):
在左侧菜单中,选择扩展→附加组件管理器→选项
里面有一个"启用拖拽手势"的选项,取消这个勾它就不会拖拽然后搜索了。
但是不是所有用户都会去关掉这个东西再访问你的网站的,我们从源码下手,阻止Firefox。
我这个例子的源代码如下:
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>拖放事件练习</title> 7 <style> 8 div { 9 width:200px; 10 height:200px; 11 background-color:yellow; 12 border:1px solid black; 13 } 14 p { 15 background-color:red; 16 } 17 </style> 18 </head> 19 20 <body> 21 22 <!-- ondrop:在指定区域松开鼠标后触发事件 ondragover:有元素拖拽到上面时触发 --> 23 <div class="droptarget" ondrop="drop(event)" ondragover="dragOver(event)"> 24 <!-- draggable:允许拖动 ondragstart:开始拖动元素触发 --> 25 <p id="p1" draggable="true" ondragstart="dragStart(event)">一个p元素</p> 26 </div> 27 28 <!-- ondrop:在指定区域松开鼠标后触发事件 ondragover:有元素拖拽到上面时触发 --> 29 <div class="droptarget" ondrop="drop(event)" ondragover="dragOver(event)"> 30 </div> 31 32 <script> 33 34 /* p元素开始拖动触发 */ 35 function dragStart(event) { 36 /* 37 *设置数据类型("Text")和拖动的数据的id(event.target.id),这样事件就能获取到这个元素的全部信息了 38 * dataTransfer:这个对象可以保存被拖动的数据 39 * dataTransfer.setData:设置要被保存数据的类型以及要被保存的数据; 40 */ 41 event.dataTransfer.setData("Text",event.target.id); 42 /* 一个提示信息 */ 43 console.log("开始拖动元素"); 44 } 45 46 /* 当鼠标在<div>上松开时触发 */ 47 function drop(event) { 48 /* 获取拖拽中"Text"的元素 */ 49 var data = event.dataTransfer.getData("Text"); 50 /* 将拖拽中的元素附加到这个区域中 */ 51 event.target.appendChild(document.getElementById(data)); 52 /* 一个提示信息 */ 53 console.log("元素已被拖动"); 54 } 55 56 /* 当有元素拖拽到这个区域上的时候触发 */ 57 function dragOver(event) { 58 event.preventDefault(); 59 } 60 </script> 61 62 </body> 63 64 </html>
百度上前人的笔记,拖拽搜索是在ondrop事件触发的时候执行的,在这个事件触发的时候我们去禁止它的事件冒泡行为。
那这里我们修改<p>元素的活动范围,也就是两个<div>区域的ondrop事件执行的函数drop():
1 function drop(event) { 2 /* 禁止冒泡行为 */ 3 event.stopPropagation(); 4 /* 获取拖拽中"Text"的元素 */ 5 var data = event.dataTransfer.getData("Text"); 6 /* 将拖拽中的元素附加到这个区域中 */ 7 event.target.appendChild(document.getElementById(data)); 8 /* 一个提示信息 */ 9 console.log("元素已被拖动"); 10 }
标红加粗的代码就是我新加的代码,这个时候我们再去测试一下<p>在两个<div>区域中拖来拖去是不是不会触发搜索了:
诶,这回不会触发搜索了,但是却跳转到另一个页面去了,这个页面的链接是"拖动元素.com",我拖动的元素id="p1",它打开了一个"p1.com"的网站。
然鹅这个问题百度上前辈的笔记并没有提到,但是却有解决办法,那就是在ondrop事件触发的时候,禁止触发事件元素的默认行为(我查到的资料都是这两条一起写,说一个禁止冒泡一个禁止默认行为,却没人提到为什么会跳转到新的页面):
1 function drop(event) { 2 /* 禁止冒泡行为 */ 3 event.stopPropagation(); 4 /* 禁止默认行为 */ 5 event.preventDefault(); 6 /* 获取拖拽中"Text"的元素 */ 7 var data = event.dataTransfer.getData("Text"); 8 /* 将拖拽中的元素附加到这个区域中 */ 9 event.target.appendChild(document.getElementById(data)); 10 /* 一个提示信息 */ 11 console.log("元素已被拖动"); 12 }
标红加粗的代码就是我新加的代码,接下来我们再去测试一下:
这个时候运行效果就跟在Chrome中一样啦。
不过因为我们禁止它冒泡和禁止默认行为是在<div>的ondrop事件触发时执行的函数中定义的,所以你把元素拖拽到其它地方还是会触发的。咱可以去设置<body>触发ondrop事件的时候去禁止冒泡和禁止默认行为。
看似问题解决了,然鹅我还是不清楚为啥禁用默认行为前Firefox会跳转到新的页面去,大概是我搜索的姿势不对吧。我找了一上午,找不到突破口,先把目前已知的部分写下来整理下思路,再继续找一找原因啦。(完了,你这个懒鬼一般说完这句话基本上后面都不会去理会这个问题的[○・`Д´・ ○])
如果这篇文章没有更新,那就是我还没有找到原因,并且放弃思考不去深究,打算学深了再回来看这个问题。如果有哪位dalao找到了原因,如果可以的话希望您能留言或者发邮件告诉我帮助我完成这篇笔记,谢谢啦!(( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)你个懒鬼!)
2019-01-28