前面的话
拖放(drag-and-drop,DnD)其实是两个动作——拖和放。所以,它涉及到两个元素。一个是被拖的元素,称为拖放源;另一个是要放的目标,称为拖放目标。本文将通过拆分这两个概念来详细介绍原生拖放
拖放源
什么样的元素才是拖放源呢?
HTML5为所有HTML元素规定了一个draggable属性,表示元素是否可以拖动
图像和链接的draggable属性自动被设置成了true,而其他元素这个属性的默认值都是false
[注意]必须设置draggable='true'才能生效,只设置draggable不起作用
默认情况下,文本只有在被选中的情况下才能拖动,而图像和链接在任何时候都可以拖动。而其他元素则无法被拖放
<input value="文字可拖动"> <img alt="图像可拖动" src="http://files.cnblogs.com/files/xiaohuochai/zan.gif"> <a href="#">链接可拖动</a> <div id="test" style="height:30px;width:300px;background:pink;">元素不可拖动</div>
当为元素设置draggable属性后,普通元素也可以拖动
<div draggable="true" style="height:30px;width:100px;background:pink;"></div>
兼容
IE9-浏览器不支持draggable属性,但可通过mousedown事件处理程序调用dragDrop()方法来实现拖动效果
<div id="test" style="height:30px;width:300px;background:pink;"></div> <script> test.onmousedown = function(){ this.dragDrop(); } </script>
[注意]如果让firefox支持draggable属性,必须添加一个ondragstart事件处理程序,并在dataTransfer对象使用setData()方法来启动效果
拖放事件
拖放源涉及到3个拖放事件。拖动拖放源时,依次触发dragstart、drag和dragend这3个事件
dragstart
按下鼠标键并开始移动鼠标时,会在被拖放的元素上触发dragstart事件。此时光标变成“不能放”符号(圆环中有一条反斜线),表示不能把元素放到自己上面
drag
触发dragstart事件后,随即会触发drag事件,而且在元素被拖动期间会持续触发该事件
dragend
当拖动停止时(无论是把元素放到了有效的放置目标,还是放到了无效的放置目标上),会触发dragend事件
<div id="test" draggable="true" style="height:30px;width:100px;background:pink;">0</div> <script> var timer,i=0; test.ondragstart = function(){ this.style.backgroundColor = 'lightgreen'; } test.ondrag = function(){ if(timer) return; timer = setInterval(function(){ test.innerHTML = i++; },100) } test.ondragend = function(){ clearInterval(timer); timer = 0; this.style.backgroundColor = 'pink'; } </script>
拖放目标
拖放目标是指被拖动的元素松开鼠标时被放置的目标
拖放源被拖动到拖放目标上时,将依次触发dragenter、dragover和dragleave或drop这四个事件
dragenter
只要有元素被拖动到放置目标上,触发dragenter事件
dragover
被拖动的元素在放置目标的范围内移动时,持续触发dragover事件
dragleave
如果元素被拖出了放置目标,触发dragleave事件
drop
如果元素被放到了放置目标中,触发drop事件
[注意]firefox浏览器的drop事件的默认行为是打开被放到放置目标上的URL。为了让firefox支持正常的拖放,还要取消drop事件的默认行为
默认情况下,目标元素是不允许被放置的,所以不会发生drop事件。只要在dragover和dragenter事件中阻止默认行为,才能成为被允许的放置目标,才能允许发生drop事件。此时,光标变成了允许放置的符号
<div id="test" draggable="true" style="height:30px;width:130px;background:pink;float:left;">拖放源</div> <div id="target" style="float:right;height: 200px;width:200px;background:lightblue;">拖放目标</div> <script> var timer,i=0; var timer1,i1=0; //兼容IE8-浏览器 test.onmousedown = function(){ if(this.dragDrop){ this.dragDrop(); } } test.ondragstart = function(){ this.style.backgroundColor = 'lightgreen'; this.innerHTML = '开始拖动'; } test.ondrag = function(){ if(timer) return; timer = setInterval(function(){ test.innerHTML = '元素已被拖动' + ++i + '秒'; },1000); } test.ondragend = function(){ clearInterval(timer); timer = 0;i =0; this.innerHTML = '结束拖动'; this.style.backgroundColor = 'pink'; } target.ondragenter = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } this.innerHTML = '有元素进入目标区域'; this.style.background = 'red'; } target.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } if(timer1) return; timer1 = setInterval(function(){ target.innerHTML = '元素已进入' + (++i1) + '秒'; },1000); } target.ondragleave = function(){ clearInterval(timer1); timer1 = 0;i1=0; this.innerHTML = '元素已离开目标区域'; this.style.backgroundColor = 'lightblue'; } target.ondrop = function(){ clearInterval(timer1); timer1 = 0;i1=0; this.innerHTML = '元素已落在目标区域'; this.style.backgroundColor = 'orange'; } </script>
dataTransfer对象
为了在拖放操作时实现数据交换,引入了dataTransfer对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据
dataTransfer对象有两个主要方法:getData()和setData()
getData()可以取得由setData()保存的值。setData()方法的第一个参数,也是getData()方法唯一的一个参数,是一个字符串,表示保存的数据类型,取值为"text"或"URL"
IE只定义了"text"和"URL"两种有效的数据类型,而HTML5则对此加以扩展,允许指定各种MIME类型。考虑到向后兼容,HTML5也支持"text"和"URL",但这两种类型会被映射为"text/plain"和"text/uri-list"
实际上,dataTransfer对象可以为每种MIME类型都保存一个值。换句话说,同时在这个对象中保存一段文本和一个URL不会有任何问题
[注意]保存在dataTransfer对象中的数据只能在drop事件处理程序中读取
在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以"text"格式保存在dataTransfer对象中。类似地,在拖放链接或图像时,会调用setData()方法并保存URL。然后,在这些元素被拖放到放置目标时,就可以通过getData()读到这些数据
<div>请将从这堆内容不同乱七八糟的文字中挑选一些移动到拖放目标中</div> <div id="target" style="margin-top:20px;height: 100px;width:200px;background:lightblue;">拖放目标</div> <div id="result"></div> <script> target.ondragenter = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } this.innerHTML = '有元素进入目标区域'; this.style.background = 'red'; } target.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } } target.ondragleave = function(e){ e = e || event; this.innerHTML = '元素已离开目标区域'; this.style.backgroundColor = 'lightblue'; } target.ondrop = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } result.innerHTML = '落入目标区域的文字为:' + e.dataTransfer.getData('text'); this.innerHTML = '元素已落在目标区域'; this.style.backgroundColor = 'orange'; } </script>
当然,也可以在dragstart事件处理程序中调用setData(),手动保存自己要传输的数据,以便将来使用
<div id="test" draggable="true" data-value="这是一个秘密" style="height:30px;width:100px;background:pink;">拖动源</div> <div id="target" style="margin-top:20px;height: 100px;width:200px;background:lightblue;">拖放目标</div> <div id="result"></div> <script> //兼容IE8-浏览器 test.onmousedown = function(){ if(this.dragDrop){ this.dragDrop(); } } test.ondragstart = function(e){ e = e || event; e.dataTransfer.setData('text',test.getAttribute('data-value')); } target.ondragenter = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } this.innerHTML = '有元素进入目标区域'; this.style.background = 'red'; } target.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } } target.ondragleave = function(e){ e = e || event; this.innerHTML = '元素已离开目标区域'; this.style.backgroundColor = 'lightblue'; } target.ondrop = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } result.innerHTML = '落入目标区域的文字为:' + e.dataTransfer.getData('text'); this.innerHTML = '元素已落在目标区域'; this.style.backgroundColor = 'orange'; } </script>
改变光标
利用dataTransfer对象,不仅可以传输数据,还能通过它来确定被拖动的元素以及作为放罝目标的元素能够接收什么操作。为此,需要访问dataTransfer对象的两个属性:dropEffect和effectAllowed
实际上,这两个属性并没有什么用,只是拖动源在拖动目标上移动时,改变不同的光标而已(但是,有一种情况除外)
dropEffect
dropEffect属性可以知道被拖动的元素能够执行哪种放置行为。这个属性有下列4个可能的值
"none":不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值(此时,将无法触发drop事件)
"move":应该把拖动的元素移动到放置目标
"copy":应该把拖动的元素复制到放置目标
"link":表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)
在把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号
[注意]必须在ondragover事件处理程序中针对放置目标来设置dropEffect属性
effectAllowed
dropEffect属性只有搭配effectAllowed属性才有用。effectAllowed属性表示允许拖动元素的哪种dropEffect
effectAllowed属性可能的值如下
"uninitialized":没有给被拖动的元素设置任何放置行为
"none":被拖动的元素不能有任何行为
"copy":只允许值为"copy"的dropEffect
"link"只允许值为"link"的dropEffect
"move":只允许值为"move"的dropEffect
"copyLink":允许值为"copy"和"link"的dropEffect
"copyMove":允许值为"copy"和"move"的dropEffect
"linkMove":允许值为"link"和"move"的dropEffect
"all":允许任意dropEffect
[注意]必须在ondragstart事件处理程序中设置effectAllowed属性
<div id="test" draggable="true" style="height:30px;width:100px;background:pink;display:inline-block;">拖放源</div> <br> <div id="target1" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(none)拖放目标</div> <div id="target2" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(move)拖放目标</div> <div id="target3" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(copy)拖放目标</div> <div id="target4" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(link)拖放目标</div> <div id="result"></div> <script> //兼容IE8-浏览器 test.onmousedown =function(){ if(this.dragDrop){ this.dragDrop(); } } test.ondragstart = function(e){ e = e || event; //兼容firefox浏览器 e.dataTransfer.setData('text',''); e.dataTransfer.effectAllowed = 'all'; } target1.ondragenter = target2.ondragenter =target3.ondragenter =target4.ondragenter =function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; }this.style.background = 'red'; } target1.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } e.dataTransfer.dropEffect = 'none'; } target2.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } e.dataTransfer.dropEffect = 'move'; } target3.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } e.dataTransfer.dropEffect = 'copy'; } target4.ondragover = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } e.dataTransfer.dropEffect = 'link'; } target1.ondragleave = target2.ondragleave =target3.ondragleave =target4.ondragleave =function(e){ e = e || event; this.style.backgroundColor = 'lightblue'; } target1.ondrop = target2.ondrop =target3.ondrop =target4.ondrop =function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } this.style.backgroundColor = 'orange'; } </script>
以上所述是小编给大家介绍的JavaScript原生拖放,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
本文向大家介绍简单谈谈原生js的math对象,包括了简单谈谈原生js的math对象的使用技巧和注意事项,需要的朋友参考一下 Math对象方法 这就是一些Math对象方法,希望能帮到大家!!!!!! 以上这篇简单谈谈原生js的math对象就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。
本文向大家介绍小白谈谈对JS原型链的理解,包括了小白谈谈对JS原型链的理解的使用技巧和注意事项,需要的朋友参考一下 原型链理解起来有点绕了,网上资料也是很多,每次晚上睡不着的时候总喜欢在网上找点原型链和闭包的文章看,效果极好。 不要纠结于那一堆术语了,那除了让你脑筋拧成麻花,真的不能帮你什么。简单粗暴点看原型链吧,想点与代码无关的事,比如人、妖以及人妖。 1)人是人他妈生的,妖是妖他妈生的。人和妖
本文向大家介绍谈谈你对闭包的理解?相关面试题,主要包含被问及谈谈你对闭包的理解?时的应答技巧和注意事项,需要的朋友参考一下 说明: bar在foo函数的代码块中定义。我们称bar是foo的内部函数。 在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。 简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。 闭包的意义与应用
本文向大家介绍谈谈对jquery ui tabs 的理解,包括了谈谈对jquery ui tabs 的理解的使用技巧和注意事项,需要的朋友参考一下 jquery ui 点击此处下载,也可以去官网查看文档帮助。 1 属性 1.11 ajaxOptions,当选项卡加载内容时,添加一个ajax选项。只有ajax时,添加的ajax选项才起作用。默认值为null。上面的例子中,添加了beforeSend
本文向大家介绍请谈谈你对JVM的理解?相关面试题,主要包含被问及请谈谈你对JVM的理解?时的应答技巧和注意事项,需要的朋友参考一下 Java虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。 什么是字节码?采用字节码的好处是什么? 在 Java 中,JVM可以理解的代码就叫做(
本文向大家介绍谈谈你对多态的理解?相关面试题,主要包含被问及谈谈你对多态的理解?时的应答技巧和注意事项,需要的朋友参考一下 多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在程序运行期间才能决定。因为在程序运行时才确定具体的类,这样