HTML5 新增了拖拽事件 drag,利用它可以实现把外部文件拖拽入页面中,可以实现文件的读取,上传等等功能。
拖拽,又叫拖拉、拖动,英文为 drag。
拖拽事件是 HTML5 新增的事件操作。
拖拽指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置(另一个标签),然后释放鼠标键,将该对象放在那里。
-
被拖拽对象:鼠标拖拽的内容,可以是标签,图片,文字等。
-
容器:被拖拽对象存放的新位置。
拖拽的对象有好几种,包括标签节点、图片、链接、选中的文字等等。在网页中,除了标签节点默认不可以拖拉,其它(图片 <img>
、超链接<a>
、选中的文字)都可以直接拖拉。
为了让标签节点可拖拉,可以将该标签的 draggable
属性设为true
。
<div class="small" draggable="true">
可拖动区域
</div>
定义了draggable
属性后,就可以给标签定义拖拽事件了。
注意:drag 事件与 mousemove 事件不相容,只能取其一。
1. 被拖拽对象相关事件
拖拽是由拖动与释放两部分组成,拖拽事件也分为:被拖拽对象的相关事件和容器的相关事件。
-
被拖拽对象的相关事件
事件 | 描述 |
---|---|
dragstart | 用户开始拖动元素时触发。通常在这个事件的监听函数中,指定拖拽的数据。 |
drag | 元素正在拖动时触发。拖拉过程中,在被拖拉的节点上持续触发(相隔几百毫秒) |
dragend | 用户完成元素拖动后触发。不管拖拉是否跨窗口,或者中途被取消,dragend 事件总是会触发的。 |
下面的例子展示,如何动态改变被拖拽节点的背景色。
<div id="box" class="box" draggable="true">
</div>
<script>
let box = document.getElementById("box");
box.addEventListener("dragstart",function (e) {
e.target.classList.add("dragging");
});
box.addEventListener("dragend",function (e) {
e.target.classList.remove("dragging");
});
</script>
当 div#box
被拖动的时候,会变成黄色背景。拖拽结束的时候,又变回红色背景。
2. 容器相关事件
-
容器相关事件
事件 | 描述 |
---|---|
dragenter | 当被鼠标拖动的对象进入其容器范围内时触发此事件。通常应该在这个事件的监听函数中,指定是否允许在当前节点放下(drop)拖拉的数据。如果当前节点没有该事件的监听函数,或者监听函数不执行任何操作,就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点,也是在这个事件的监听函数中设置。 |
dragover | 当被拖动的对象在另一对象容器范围内拖动时触发此事件。dragenter 事件在进入该节点时触发,然后只要没有离开这个节点,dragover 事件会持续触发。 |
dragleave | 当被鼠标拖动的对象离开其容器范围时触发此事件 |
drop | 被拖拉的节点或选中的文本,松开鼠标释放到容器节点时,在容器节点上触发。 注意,如果当前节点不允许drop ,或者用户按下 ESC 键,取消这个操作,不会触发该事件。 该事件的监听函数负责取出拖拉数据,并进行相关处理。 |
注意:
-
默认情况下,浏览器阻止任何东西向HTML元素放置拖拽的发生。
-
要在容器(可放置区域)设置阻止默认事件
event.preventDefault()
,否则drop
事件不会被触发。 -
一般阻止默认事件是写在
dragover
、drop
事件上。
下面的例子展示,如何实现将一个节点从当前父节点,拖拉到另一个父节点中。
<div class="dropzone">
<div id="box" class="box" draggable="true">
要拖动的div
</div>
</div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<script>
let box = document.getElementById("box");
let dropzone = document.querySelectorAll(".dropzone");
box.addEventListener("dragstart",function (e) {
let _box = this;
// 开始拖拽的时候,让原来的 div 隐藏,要通过延迟代码执行。
setTimeout(function () {
_box.style.opacity = 0;
},0);
});
box.addEventListener("dragend",function (e) {
// 结束拖拽,原来的div恢复显示。
e.target.style.opacity = 1;
});
dropzone.forEach(function (item,index) {
item.addEventListener("dragenter",function (e) {
e.target.classList.add("over");
});
item.addEventListener("dragover",function (e) {
// 阻止默认事件
e.preventDefault();
});
item.addEventListener("dragleave",function (e) {
e.target.classList.remove("over");
});
item.addEventListener("drop",function (e) {
e.preventDefault(); // 阻止默认事件
// 把 div.box放入对应的div.dropzone 中
e.target.appendChild(box);
});
});
</script>
3. drag 事件执行顺序
-
dragstart (被拖拽元素)
-
dragenter(容器)
-
dragover (容器)
-
dragleave(容器)
-
drop (容器)
-
dragend (被拖拽元素)
从 dragstart
开始,到 dragend
为止,整个过程都在连续触发 drag (被拖拽元素)。如下图所示,仅保留 dragstart、drag、dragend 事件。
4. 案例:拖拽图片文件到页面中
(1)准备
拖拽文件到页面 div.box 标签中。样式自定。
<div class="box" id="box">
<span>把文件拖放在这里</span>
</div>
必须给 dragover
添加禁止默认事件代码。
box.addEventListener("dragover",function (e) {
e.preventDefault();
});
(2)DataTransfer.files
event.dataTransfer.files
属性是一个 FileList 对象,包含一组本地文件,可以用来在拖拉操作中传送。如果本次拖拉不涉及文件,则该属性为空的 FileList 对象。
可以遍历 FileList,也可以利用索引获取某个 file ,并获取file 的 name,type,size 等属性。
let box = document.getElementById("box");
box.addEventListener("dragover",function (e) {
e.preventDefault();
});
box.addEventListener("drop",function (e) {
e.preventDefault();
let file = e.dataTransfer.files[0];
console.info( e.dataTransfer.files )
console.info( file )
console.info( file.name )
console.info( file.type )
console.info( file.size )
});
可以利用 URL.createObjectURL(file)
静态方法获取 file 的路径。
(3)拖拽单张图片到页面中
box.addEventListener("drop",function (e) {
e.preventDefault();
box.innerHTML = "";
// 获取文件
let file = e.dataTransfer.files[0];
// 获取文件 type
console.info( file.type );
// 判断文件是否是图片
if( /image/.test(file.type)){
console.info("图片");
}else{
box.innerHTML = "请拖入一个图片文件,如png,jpg或者gif";
return false; // 终止函数运行
}
// 生成文件路径
let url = URL.createObjectURL(file);
// 创建一个 img 标签
let img = document.createElement("img");
img.src = url;
// 把 img 添加到 box 里。
box.appendChild(img)
});
(4)拖拽多张图片到页面中
box.addEventListener("drop",function (e) {
e.preventDefault();
box.innerHTML = "";
// 获取文件列表
let files = e.dataTransfer.files;
[...files].forEach(function (item,index) {
// 判断文件是否是图片
if( /image/.test(item.type)){
console.info("图片");
// 生成文件路径
let url = URL.createObjectURL(item);
// 创建一个 img 标签
let img = document.createElement("img");
img.src = url;
// 把 img 添加到 box 里。
box.appendChild(img)
}else{
console.info(`文件${index}不是图片`);
}
});
});