第73节 拖放(Drag and Drop API)上-前端开发之JavaScript-王唯

拖放(或称为拖拽)就是用户可使用鼠标选择可拖放元素(draggable),将其拖拽到可放置元素(droppable),并释放鼠标以放置这些元素;在此期间,会有一个可拖放元素的半透明元素副本跟随鼠标移动,并且会触发一系列事件;

最早在网页中引入拖放功能的是IE4,当时,网页中只有两种对象可以拖放:图像和文本,但是只有文本框可以当作放置目标;在IE5中,扩展了拖放的功能,添加了新的事件,并且几乎所有元素都可以作为放置目标;到了IE6,可以让页面中的任何元素都可以拖放;
后来,HTML5以IE的拖放功能为基础,制定了拖放的规范(HTML5 Drag和Drop API),并且,现代浏览器都支持HTML5的拖放API,而且也可以在框架间、窗口间,甚至在应用间进行拖放;
在实际的应用中,需要定义什么元素是可以拖放的、当拖放事件发生时如何处理,以及定义可放置的元素。

可拖动元素(draggable):
默认情况下,图像、链接和文本是可以拖动的;让其他元素可以拖动,可以利用HTML5为所有HTML元素定义的一个draggable属性,表示元素是否可以拖动,该属性是一个枚举属性,可能的值有”true”和”false”;

<p>零点程序员</p>
<p><img src="images/1.jpg" style="width:200px;" /></p>
<script>
var p = document.getElementsByTagName("p")[0];
var img = document.getElementsByTagName("img")[0];
console.log(p.draggable); // false
console.log(img.draggable); // true
</script>

要想让其他元素可拖动,或让图像或链接不能拖动,就可以设置这个属性,如:

<p>零点程序员</p>
<p><img src="images/1.jpg" style="width:200px;" draggable="false" /></p>
<div id="container" draggable="true"></div>
<script>
var p = document.getElementsByTagName("p")[0];
var img = document.getElementsByTagName("img")[0];
p.draggable = true;
console.log(p.draggable); // true
img.draggable = false;
console.log(img.draggable); // false
</script>

某些低版本的浏览器不支持HTML5的拖放功能;
注意:当一个元素被设置成可拖动时,元素中的文本和其他子元素不能以正常的方式被选中,此时,用户必须按住Alt,再用鼠标选择文本,或者使用键盘选择;

拖放事件:
一个典型的拖放操作是,用户选中一个可拖放的元素,并将其拖动(鼠标不放开)到一个可放置的元素上面,然后释放鼠标;在此操作期间,会触发一系列事件,并且有一些事件会被多次触发;
通过这些拖放事件,可以控制拖放相关的各个方面;其中最关键的地方在于确定哪里发生了拖放事件,有些事件是在被拖动的元素上触发的,而有些事件是在放置目标上触发的;

拖动某元素时,将依次触发下列事件:

dragstart:当开始拖动一个元素或选中的文本时触发,可以冒泡;drag:当拖动元素或选中的文本时反复触发;dragend:当拖放操作结束后触发,即松开鼠标或按“ESC”键;

这三个事件的事件目标都是被拖动的元素;

// 拖放目标
var img = document.getElementsByTagName("img")[0];
function handler(event){
// console.log(event); // DragEvent
console.log(event.type);
}
img.addEventListener("dragstart", handler, false);
img.addEventListener("drag", handler, false);
img.addEventListener("dragend", handler, false);

按下鼠标并开始移动鼠标时,会在被拖放的元素上触发dragstart事件,此时光标变成“不能放”的符号(圆环中有一条反斜线),表示不能把元素放到自己上面;默认情况下,大多数浏览器会为正被拖动的元素创建一个半透明的副本,这个副本始终跟随着光标移动;

触发dragstart事件后,随即会触发drag事件,而且在元素被拖动期间会持续触发该事件;这个事件与mousemove事件相似;当拖动停止时(无论是把元素放到了有效的放置目标,还是放到了无效的放置目标上),就会触发dragend事件;

浏览器不会在拖动期间改变被拖动元素的外观,但开发者可以自己修改,并且,在dragstart事件中,还可以设置一些参数,如:

img.addEventListener("dragstart", function(event){
event.target.style.border = "dashed 2px #F00";
}, false);

dragend事件可以重设样式或者别的页面展示动作;如:

img.addEventListener("dragend", function(event){
event.target.style.border = "none";
}, false);

drag事件会持续触发,一般被用来监测被拖拽元素的位置;

img.addEventListener("drag", function(event){
console.log(event);
});

注意:当从操作系统向浏览器中拖放文件时,不会触发dragstart、drag以及dragend事件;
当某个元素被拖动到一个有效的放置目标上时,下列事件会依次发生:

dragenter:当拖动元素或选中的文本到一个可放置目标时触发;dragover:当元素或选中的文本被拖动一个可放置目标上反复触发(每100毫秒触发一次);dragleave:当拖动元素或选中的文本离开一个可放置目标时触发;或drop:当元素或选中的文本在可放置目标上被放置时触发;

这四个事件的事件目标都是作为放置目标的元素;

<div id="container" ondragover="return false;" style="width: 400px;height:300px;border:solid 1px #F0F;"></div>
<script>
function handler(event){
// console.log(event); // DragEvent
console.log(event.type);
}
// 放置目标
var container = document.getElementById("container");
container.addEventListener("dragenter", handler, false);
container.addEventListener("dragover", handler, false);
container.addEventListener("dragleave", handler, false);
container.addEventListener("drop", handler, false);
</script>

只要有元素被拖动到放置目标上,就会触发dragenter事件,其会在拖动元素50%部分进入放置区域的时候被触发;紧随其后的是dragover事件,而且在被拖动的元素还在放置目标的范围内移动时,会持续触发该事件(类似于拖动元素的drag事件);如果元素被拖出了放置目标之外,会触发dragleave事件;如果元素被放到了放置目标中,则会触发drop事件,但不会触发dragleave事件;

dragenter事件处理程序可以设置拖放数据、设置放置元素的样式等;dragover事件可以被用来侦听被拖动元素的准确位置;dragleave事件通常被用来移除dragenter或者dragover的样式;drop事件通常被用来添加或移除元素、设置样式或读取数据;

container.addEventListener("dragenter", function(event){
event.target.style.border = "solid 2px #00F";
}, false);
container.addEventListener("dragover", function(event){
event.preventDefault();
})
container.addEventListener("dragleave", function(event){
event.target.style.border = "solid 2px #000";
}, false);
container.addEventListener("drop", function(event){
event.target.style.border = "solid 2px #0F0";
event.target.appendChild(img);
}, false);

对于拖动元素和放置目标元素来说,其事件发生的次序为:
dragstart->drag(反复)->dragenter->dragover->drag(dragover与drag交替反复)->(drop | dragleave)->dragend;
一旦拖动完成,dragend就会触发,无论拖动成功还是被取消,该事件都会被触发。

自定义(指定)放置目标:
在拖动元素经过某些无效放置目标时,可以看到一个种特殊的光标(圆环中有一条反斜线),表示不能放置拖动元素;虽然所有元素都支持放置目标事件,但这些元素默认是不允许放置的;如果拖动元素经过不允许放置的元素,无论用户如何操作,都不会发生drop事件;
在dragenter和dragover事件中返回false,或者取消默认行为就可以让任何元素变成有效的放置目标,如:

<div id="container" ondragover="return false;"> </div>

或:

var container = document.getElementById("container");
container.addEventListener("dragenter", function(event){
event.preventDefault();
},false);
container.addEventListener("dragover", function(event){
event.preventDefault();
},false);

此时,当拖动元素移动到放置目标上时,光标变成了允许放置的符号,并且,释放鼠标时也会触发drop事件;
Firefox默认情况下是可以放置的,即不需要在dragenter和dragover事件取消默认行为也可以触发drop事件;
通常希望只在某些情况下调用preventDefault()方法,此时,可以检查某种条件,并且只在满足条件时才取消事件,否则不取消事件,用户释放鼠标按钮不会执行放置动作,如:

container.ondragover = function(event){
if(event.ctrlKey){
event.preventDefault();
event.target.innerText = "可以放置";
}
};

在Firefox中,drop放置事件的默认行为是打开被放到放置目标上的URL,例如,如果拖动的是图片或链接,会在新窗口或放置目标上打开该图片或链接,如果拖动的是选中的文本,也会在新窗口中打开,并调用浏览器设置的默认搜索引擎,并把选中的文本传递过去,如:

container.addEventListener("drop", function(event){
event.preventDefault();
},false);
// document.body.addEventListener("drop", function(event){
// event.stopPropagation();
// event.preventDefault();
// },false);
// 或者
document.documentElement.addEventListener("drop", function(event){
event.stopPropagation();
event.preventDefault();
},false);
示例:拖放排序
<ul>
<li draggable="true" class="list">HTML</li>
<li draggable="true" class="list">CSS</li>
<li draggable="true" class="list">JavaScript</li>
</ul>
<script>
var source = document.querySelectorAll('.list'),
dragElement = null;
for(var i = 0; i < source.length; i++){
source[i].addEventListener('dragstart',function(ev){
dragElement = this;
},false);
source[i].addEventListener('dragenter', function(ev){
if(dragElement != this){
this.parentNode.insertBefore(dragElement,this);
}
}, false)
source[i].addEventListener('dragleave', function(ev){
if(dragElement != this){
if(this == this.parentNode.lastElementChild || this == this.parentNode.lastChild){
this.parentNode.appendChild(dragElement);
}
}
}, false)
};
document.ondragover = function(e){e.preventDefault();}
document.ondrop = function(e){e.preventDefault();}
</script>

DragEvent类:
拖放事件对象属于DragEvent类,该类表示一个拖、放交互的一个接口,其继承自MouseEvent和Event类;

container.addEventListener("drop", function(event){
event.preventDefault();
console.log(event); // DragEvent
}, false);

拖放数据dataTransfer对象:
为了在拖放操作时实现数据交换,IE5引入了dataTransfer对象,它是事件对象的一个只读属性,用于从被拖动元素向放置目标传递字符串格式的数据,该数据必须与被拖动的元素相关联;

var container = document.getElementById("container");
container.addEventListener("drop", function(event){
console.log(event.type);
console.log(event.dataTransfer); // DataTransfer
console.log(event.dataTransfer.getData("text"));
console.log(event.dataTransfer.getData("url"));
}, false);

dataTransfer对象是属于DataTransfer类型;因为它是事件对象的属性,所以只能在拖放事件处理程序中访问dataTransfer对象;用这个对象的属性和方法,可以来完善拖放的功能。

DataTransfer类:
该类对象用于保存拖动并放置(drag and drop)过程中的数据,其可以保存一项或多项数据,并且这些数据项可以是一种或者多种数据类型;另外,其还包含了拖动事件的状态和类型,例如copy或move;

dataTransfer对象有两个主要方法:
setData(type, data)方法:用来设置给定类型的数据;参数type是一个字符串,用于指定保存的数据类型,取值为“text”和“URL”,参数data为保存的数据值;
该方法必须在dragstart事件中设置,否则不起作用;

img.addEventListener("dragstart", function(event){
event.dataTransfer.setData("text", "Web前端开发");
event.dataTransfer.setData("URL", "https://www.zeronetwork.cn");
});

每一个type中只能设置一个data;

getData(type)方法:
获取给定类型的数据,如果该类型的数据不存在或dataTransfer不包含数据,则返回空字符串;参数type为数据类型;
该方法只能在放置对象的drop事件中调用;

var container = document.getElementById("container");
container.addEventListener("drop", function(event){
var text = event.dataTransfer.getData("text");
console.log(text);
var url = event.dataTransfer.getData("URL");
console.log(url);
}, false);
// 该事件是令container成为放置对象
container.addEventListener("dragover", function(event){
event.preventDefault();
}, false);

如果在其他事件处理程序中调用此方法,返回空值,原因是为了在传输过程中保护数据;

示例:拖入一个段落和链接

var p = document.getElementsByTagName("p")[0];
p.addEventListener("dragstart", function(event){
event.dataTransfer.setData("text", event.target.id);
event.dataTransfer.setData("URL", "https://www.zeronetwork.cn");
event.target.style.backgroundColor = "green";
},false);
var container = document.getElementById("container");
container.addEventListener("drop", function(event){
event.preventDefault();
var data = event.dataTransfer.getData("text");
event.target.appendChild(document.getElementById(data));
var url = event.dataTransfer.getData("URL");
var a = document.createElement("a");
a.href = url;
a.textContent = url;
event.target.appendChild(a);
document.getElementById(data).style.backgroundColor = "";
}, false);

一般来说,在拖动开始时,即在拖动元素的dragstart事件中,设置数据类型和数据值;在放置元素的drop事件中,获取数据,并将其插入到放置位置;最后在dragend事件中,处理一些收尾工作;

示例:拖拽DIV块

<style>
#container {width: 1000px; height: 100%; margin: 0 auto;}
#container div{
width: 200px; height: 200px; float: left; margin-left:20px;
}
#div1 {border: 5px solid blue;}
#div2 {border: 5px solid yellow;}
#div3 {border: 5px solid green;}
#container p {
background-color: orange;
margin-top: 5px; height:50px; line-height:50px;
}
</style>
<div id="container">
<div id="div1">
<p id="p1" draggable="true">Web前端开发</p>
<p id="p2" draggable="true">大师哥王唯</p>
</div>
<div id="div2"></div>
<div id="div3"></div>
</div>
<script>
var parentNode = null;
document.addEventListener("dragstart", function (event) {
event.target.style.opacity=0.5;
parentNode = event.target.parentNode;
parentNode.style.borderStyle="dashed";
event.dataTransfer.setData("text/plain",event.target.id);
},false);
document.addEventListener("dragend", function (event) {
event.target.style.opacity=1;
parentNode.style.borderStyle="solid";
parentNode = null;
},false);
document.addEventListener("dragenter", function (event) {
event.preventDefault();
});
document.addEventListener("dragover", function (event) {
event.preventDefault();
});
document.addEventListener("drop", function (event) {
event.preventDefault();
var id = event.dataTransfer.getData("text/plain");
if ((parentNode !== event.target.parentNode) && (event.target.parentNode !== document)) {
event.target.appendChild(document.querySelector("#"+id));
}
},false);
</script>

如果在drop事件中没有读取到,说明dataTransfer对象已经被销毁,保存的数据也丢失了;

默认情况下,在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以“text”格式保存在dataTransfer对象中;类似地,在拖放链接或图像时,会调用setData()方法并保存URL;然后,在这些元素被拖放到放置目标时,就可以通过getData()读取到这些数据;

将数据保存为text和保存为URL是有区别的;如果保存为text格式,那么数据不会得到任何特殊处理;而如果保存为URL,浏览器会将其当成页面中的链接;

另外在Firefox中,如果在dragstart事件处理函数中调用了setData()方法,会打开新窗口,如:

var p = document.getElementsByTagName("p")[0];
p.addEventListener("dragstart", function(event){
event.dataTransfer.setData("text", event.target.id);
},false);

clearData([type]):清除给定格式保存的数据;
type参数是可选的,如果省略此参数,则所有类型的数据都会被删除;

var p = document.getElementsByTagName("p")[0];
p.addEventListener("dragstart", function(event){
event.dataTransfer.setData("text", "零点网络");
event.dataTransfer.setData("URL", "https://www.zeronetwork.cn");

console.log(event.dataTransfer.getData("text")); // 零点网络
console.log(event.dataTransfer.getData("URL")); // 零点网络
// event.dataTransfer.clearData("text");
event.dataTransfer.clearData();
console.log(event.dataTransfer.getData("text")); // 获取不到
console.log(event.dataTransfer.getData("URL")); // 获取不到
},false);

该方法只能在dragstart事件的处理程序中使用;
此方法不会从拖动操作中删除文件,因此如果有任何文件包含在对象的DataTransfer.types列表中,仍然可能存在一个类型为“Files”的数据;

示例:拖动一个元素

<style>
span.tweaked{display: inline-block; margin: 1em 0; padding: 1em 2em;}
#source{color:blue; border:1px solid black;}
#target{border:1px solid black;}
</style>
<span class="tweaked" id="source" draggable="true">选择此元素,将其拖动到放置区域</span>
<span class="tweaked" id="target">放置区域</span>
<div>状态:<span id="status">开始拖动</span></div>
<div>数据:<span id="data">uninitialized</span></div>
<script>
window.addEventListener("DOMContentLoaded", function(){
var draggable = document.getElementById("source");
var droppable = document.getElementById("target");
var status = document.getElementById("status");
var data = document.getElementById("data");
var droped = false;
draggable.addEventListener("dragstart", dragStartHandler, false);
draggable.addEventListener("dragend", dragEndHandler, false);
droppable.addEventListener("dragover", dragOverHandler, false);
droppable.addEventListener("dragleave", dragLeaveHandler, false);
droppable.addEventListener("drop", dropHandler, false);
function dragStartHandler(event){
status.innerHTML = "拖动进行中...";
event.currentTarget.style.border = "1px dashed blue";
event.dataTransfer.clearData();
event.dataTransfer.setData("text", event.target.id);
data.innerHTML = event.dataTransfer.getData("text");
}
function dragEndHandler(event){
if(!droped)
status.innerHTML = "取消拖动";
data.innerHTML = event.dataTransfer.getData("text") || "empty";
event.currentTarget.style.color = "1px solid black";
if(droped){
draggable.removeEventListener("dragstart",dragStartHandler,false);
draggable.removeEventListener("dragend", dragEndHandler, false);
droppable.removeEventListener("dragover", dragOverHandler, false);
droppable.removeEventListener("dragleave", dragLeaveHandler,false);
droppable.removeEventListener("drop", dropHandler, false);
}
}
function dragOverHandler(event){
event.preventDefault();
status.innerHTML = "可以放置...";
}
function dragLeaveHandler(event){
event.preventDefault();
status.innerHTML = "拖入过程(不能放置)";
}
function dropHandler(event){
event.preventDefault();
droped = true;
status.innerHTML = "拖放结束";
var _data = event.dataTransfer.getData("text");
var element = document.getElementById(_data);
event.target.appendChild(element);
element.style.cssText = "border:1px solid black; display:block; color:red";
element.innerHTML = "已经放置到目标区域";
}
},false);
</script>

拖动数据类型:

IE中只支持“text”和”URL”两种数据类型,而HTML5进行了扩展,允许指定各种MIME类型,例如text/plain、text/uri-list、text/html、text/xml、Files等;

拖动文本或链接:

var p = document.getElementsByTagName("p")[0];
p.addEventListener("dragstart", function(event){
event.dataTransfer.setData("text/plain","大师哥王唯");
event.dataTransfer.setData("text/uri-list","https://www.zeronetwork.cn");
},false);
document.addEventListener("dragover", function(event){
event.preventDefault();
});
document.addEventListener("drop", function(event){
var dt = event.dataTransfer;
var text = dt.getData("text/plain");
var url = dt.getData("text/uri-list");
console.log(text);
console.log(url);
},false);

要拖动多个链接,还可以使用换行符分隔每个链接,如:

event.dataTransfer.setData("text/uri-list","https://www.zeronetwork.cn\\r\\nhttps://cn.bing.com");

获取时,如:

var urls = event.dataTransfer.getData("text/uri-list");
console.log(urls);
urls = urls.split("\\r\\n");

还可以使用Mozilla特定类型text/x-moz-url的数据,其数据值包含链接的URL,后跟链接的标题,用换行符分隔,例如:

event.dataTransfer.setData("text/x-moz-url","https://www.zeronetwork.cn\\r\\n王唯");

获取时,如:

var urls = event.dataTransfer.getData("text/x-moz-url").split("\\r\\n");
console.log(urls); // ['https://www.zeronetwork.cn', '王唯']

IE并不支持这些MIME类型,考虑到向后兼容,HTML5也支持“text”和“URL”,但这两种类型会被映射为“text/plain”和“text/uri-list”;
由于IE遇到新类型,会抛出异常,所以使用try/catch语句兼容IE的方案:

p.addEventListener("dragstart", function(event){
try {
event.dataTransfer.setData("text/plain","大师哥王唯");
event.dataTransfer.setData("text/uri-list","https://cn.bing.com");
} catch (e) {
event.dataTransfer.setData("text","零点程序员");
event.dataTransfer.setData("URL","https://www.zeronetwork.cn");
}
},false);
container.addEventListener("drop", function(event){
event.preventDefault();
var text,url;
try{
text = event.dataTransfer.getData("text/plain");
url = event.dataTransfer.getData("text/uri-list");
}catch(e){
text = event.dataTransfer.getData("text");
url = event.dataTransfer.getData("URL");
}
console.log(text);
console.log(url);
}, false);

Firefox在其第5个版本之前不能正确的将“URL”和“text”映射为“text/uri-list”和“text/plain”,但却能把“Text”(注意,T为大写)映射为“text/plain”,所以在取得文本数据时使用“Text”;

var text = dataTransfer.getData("Text");

IE不支持setData()方法设置URL类型;

示例:拖动节点

<ul>
<li id="li1" draggable="true">HTML</li>
<li id="li2" draggable="true">CSS</li>
</ul>
<div id="container"></div>
<script>
var list = document.getElementsByTagName("ul")[0];
list.addEventListener("dragstart", function(event){
try {
event.dataTransfer.setData("text/plain", event.target.id);
} catch (e) {
event.dataTransfer.setData("text", event.target.id);
}
});
container.addEventListener("drop", function(event){
event.preventDefault();
var data;
try {
data = event.dataTransfer.getData("text/plain");
} catch (e) {
data = event.dataTransfer.getData("text");
}
event.target.appendChild(document.getElementById(data));
}, false);
</script>

在标准浏览器设置其他任意值的类型字符串也能正常执行,如:

var p = document.getElementsByTagName("p")[0];
p.addEventListener("dragstart", function(event){
event.dataTransfer.setData("data","大师哥王唯");
event.dataTransfer.setData("myurl","https://www.zeronetwork.cn");
var obj = {name:"wangwei","sex":true,age:18}
event.dataTransfer.setData("person", JSON.stringify(obj));
},false);
document.addEventListener("dragover", function(event){
event.preventDefault();
});
document.addEventListener("drop", function(event){
console.log(event.dataTransfer.getData("data"));
console.log(event.dataTransfer.getData("myurl"));
console.log(event.dataTransfer.getData("person"));
var person = JSON.parse(event.dataTransfer.getData("person"));
console.log(person.name,person.sex,person.age);
},false);

IE不支持任意类型,但可以使用text类型保存序列化的对象;如:

p.addEventListener("dragstart", function(event){
var data = {text:"大师哥王唯",url:"https://www.zeronetwork.cn"}
event.dataTransfer.setData("Text", JSON.stringify(data));
},false);
document.addEventListener("dragover", function(event){
event.preventDefault();
});
document.addEventListener("drop", function(event){
var data = JSON.parse(event.dataTransfer.getData("Text"));
console.log(data.text, data.url);
},false);

拖动HTML和XML:
HTML内容可以使用text/html类型,此类型的数据应该是要拖动的序列化的HTML;
XML内容可以使用text/xml类型,但是应该确保数据值是格式良好的XML;
还可以使用text/plain类型包含HTML或XML数据的纯文本表示,数据应该只是文本,不应该包括任何源标记或属性;例如:

var p = document.getElementsByTagName("p")[0];
p.addEventListener("dragstart", function(event){
var dt = event.dataTransfer;
dt.setData("text/html", "<p>大师哥<strong>王唯</strong></p>");
dt.setData("text/plain", "是一个好人");
},false);
var container = document.getElementById("container");
container.addEventListener("drop", function(event){
event.preventDefault();
var dt = event.dataTransfer;
var html = dt.getData("text/html");
event.target.insertAdjacentHTML("beforeend", html);
var text = dt.getData("text/plain");
event.target.insertAdjacentText("beforeend", text);
});

types属性:
当前保存的数据类型的只读的数组,其数据类型以字符串的形式保存,其顺序与拖动操作中包含的数据顺序相同;

container.addEventListener("drop", function(event){
// ["text/uri-list", "text/html", "Files"]
console.log(event.dataTransfer.types);
// 打印所有格式类型
if(event.dataTransfer.types != null){
for(var i=0; i<event.dataTransfer.types.length; i++){
console.log("types["+ i +"] = " + event.dataTransfer.types[i]);
}
}
});

dataTransfer对象的setData()和getData()方法就是根据types中保存的MIME类型进行设置或获取值的,例如使用setData()方法时,如果该类型的数据不存在,则将其添加到末尾,即添加到types属性列表中的最后位置;如果该类型的数据已经存在,则在相同位置替换现有数据;

之前的规范中,types属性返回的是StringList集合,在IE中返回的就是这种集合,而最新的规范返回的是Strings数组,所以在使用types属性前应该检查它的类型,如果是集合,可以使用contains方法,如果是数组可以使用includes方法,如:

container.addEventListener("drop", function(event){
event.preventDefault();
console.log(event.dataTransfer.types);
for(var i=0,len = event.dataTransfer.types.length; i<len; i++){
console.log(event.dataTransfer.types[i]);
}
if (event.dataTransfer.types.contains) {
if(event.dataTransfer.types.contains("Text"))
console.log(event.dataTransfer.getData("Text"));
if (event.dataTransfer.types.contains("Url"))
console.log(event.dataTransfer.getData("Url"));
}else if(event.dataTransfer.types.includes){
if(event.dataTransfer.types.includes("text/plain"))
console.log(event.dataTransfer.getData("text/plain"));
if (event.dataTransfer.types.includes("text/uri-list"))
console.log(event.dataTransfer.getData("text/uri-list"));
if (event.dataTransfer.types.includes("text/html"))
console.log(event.dataTransfer.getData("text/html"));
if(event.dataTransfer.types.includes("mytype"))
console.log(event.dataTransfer.getData("mytype"));
}
}, false);

可以根据数据传输中拖拽数据的类型来接受或拒绝放置,如:

function contains(list, value){
for(var i=0; i<list.length; i++){
if(list[i] === value) return true;
}
return false;
}
container.addEventListener("dragover", function(event){
console.log(event.dataTransfer.types);
var isLink;
if (event.dataTransfer.types.contains) {
isLink = contains(event.dataTransfer.types, "Url");
}else if (event.dataTransfer.types.includes) {
isLink = contains(event.dataTransfer.types, "text/uri-list");
}
// var isLink = event.dataTransfer.types.includes("text/uri-list") ? true : false;
if(isLink)
event.preventDefault();
},false);
container.addEventListener("drop", function(event){
event.preventDefault();
console.log(event.type);
}, false);

可能需要支持不同的格式,但希望取回数据的格式是支持格式中最具体的一种,如,放置目标支持三种格式,返回格式中支持最佳的数据,如:

container.addEventListener("drop", function(event){
event.preventDefault();
var supportedTypes = ["application/x-moz-file", "text/uri-list", "text/plain"];
var types = event.dataTransfer.types.filter(function(v,i){
console.log(v);
return supportedTypes.includes(v);
});
console.log(types);
if (types.length) {
var data = event.dataTransfer.getData(types[0]);
console.log(types[0] + ":" + data);
}
});

第73节 拖放(Drag and Drop API)上-前端开发之JavaScript-王唯

本文来自投稿,不代表重蔚自留地立场,如若转载,请注明出处https://www.cwhello.com/41788.html

如有侵犯您的合法权益请发邮件951076433@qq.com联系删除

(0)
零点程序员零点程序员订阅用户
上一篇 2022年6月23日
下一篇 2022年6月23日

相关推荐

联系我们

QQ:951076433

在线咨询:点击这里给我发消息邮件:951076433@qq.com工作时间:周一至周五,9:30-18:30,节假日休息