拖拽
拖拽功能是H5里提供的一个标准。有了拖拽功能之后,为我们的网站提供了更多的交互选择。
拖拽的流程
- 拖拽元素 drap
- 释放元素 drop
源对象和目标对象
- 源对象
- 被拖拽的元素被称之为 源对象
- 目标对象
- 当拖拽的元素被放下或者划过某个元素的时候,该元素就是我们的目标对象
draggable
当你希望对某个元素进行拖拽的时候,需要为该元素设置draggable属性
链接和图像默认是可拖动的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.app {
width:200px;
height: 200px;
}
#app1 {
background-color: cyan;
}
#app2 {
background-color: orange;
}
</style>
</head>
<body>
<div id="app1" class="app " draggable="true"></div>
<div id="app2" class="app" ></div>
</body>
</html>
从上图中我们可以看出,设置了draggable的元素是可以被拖动的,而没有设置的元素则无法拖动
源对象的操作函数
- ondragstart: 源对象开始被拖动时触发
- ondrag: 源对象正在被拖动的过程中触发,会触发多次
- ondragend: 源对象拖动结束(被放下后者取消)
例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.app {
width:200px;
height: 200px;
}
#app1 {
background-color: cyan;
font-size: 28px;
}
</style>
</head>
<body>
<div id="app1"
class="app"
draggable="true"
ondragstart="dragStart()"
ondrag="draging()"
ondragend="dragEnd()"
>源对象</div>
</body>
</html>
<script>
function dragStart(){
console.log("开始拖拽");
}
function draging(){
console.log("元素正在被拖拽");
}
function dragEnd(){
console.log("拖拽结束");
}
</script>
目标对象相关方法
- ondragenter: 源对象进入目标对象范围时触发
- ondragover: 源对象在目标对象范围内拖拽时触发
- ondragleave: 源对象被拖离目标对象范围时触发
- ondrop: 源对象在目标对象范围内被释放的时候触发
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.app {
width:100px;
height: 100px;
}
#app1 {
background-color: cyan;
font-size: 28px;
}
#app2 {
width: 200px;
height: 200px;
background-color: orange;
}
</style>
</head>
<body>
<div id="app1"
class="app"
draggable="true"
>源对象</div>
<div id="app2"
ondragenter="dragenter()"
ondragover="dragover()"
ondragleave="dragleave()"
ondrop="drop()"
></div>
</body>
</html>
<script>
function dragenter(){
console.log("拖拽的元素,进入到App2的范围内");
}
function dragover(){
console.log("拖拽的元素在app2的元素内,飞来飞去");
}
function dragleave(){
console.log("拖拽的元素离开了app2元素");
}
function drop(){
console.log("拖拽的元素被放入到app2元素内");
}
</script>
在上面的例子中,我们在橙色的元素里放下蓝色的元素,但是在最终蓝色元素并没有停留在橙色区块中,而是回到原来的位置上。
dataTransfer
为了能够得到拖拽元素的相关信息,H5为每个相关的事件提供了dataTransfer对象,用于在源对象和目标对象的事件传递数据。
- setData(key,value) 保存数据
getData(key) //获取数据
取消目标元素的默认事件,否则无法放下元素
- 在拖拽的开始就记录 源对象的相关信息,
- 在目标元素上执行drop事件时,获取源对象的相关信息,并将该元素插入到目标元素上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.app {
width:100px;
height: 100px;
}
#app1 {
background-color: cyan;
font-size: 28px;
}
#app2 {
width: 200px;
height: 200px;
background-color: orange;
}
</style>
</head>
<body>
<div id="app1"
class="app"
draggable="true"
ondragstart="dragStart(event)"
>源对象</div>
<div id="app2"
ondragover="dragover(event)"
ondrop="drop(event)"
></div>
</body>
</html>
<script>
// 在滑动的过程中,取消目标元素的默认事件
function dragover(ev){
ev.preventDefault();
}
// 释放元素
function drop(ev){
// 取消元素的默认事件
ev.preventDefault();
//获取源对象的相关信息
let sourceId = ev.dataTransfer.getData('sourceId');
//获取源对象相关的元素,
let sourceElement = document.getElementById(sourceId);
//插入到目标元素中
ev.target.appendChild(sourceElement);
}
//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
ev.dataTransfer.setData('sourceId',ev.target.id)
}
</script>
实例
- 左右两个元素列表互相拖拽
需求:
- 左右两列可以互相拖拽释放元素
- 在图片上面不能放下其他元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.container {
width: auto;
height: 400px;
display: flex;
flex-direction: row;
}
.app {
width:200px;
height: 400px;
}
.app li {
width: 100%;
}
.app li img {
width: 100%;
}
#app1 {
background-color: cyan;
}
#app2 {
background-color: orange;
margin-left: 100px;
}
</style>
</head>
<body>
<div class="container">
<ul id="app1"
class="app"
ondragstart="dragStart(event)"
ondragover="dragover(event)"
ondrop="drop(event)"
>
<li draggable="true" id="li1" ondragstart="dragStart(event)" ondrop="stopDrop(event)">
<img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620194&di=ce0f0e3feda2ed250b10c8d636010e86&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F4%2F56f62bab021a8.jpg" alt="">
</li>
<li draggable="true" id="li2" ondragstart="dragStart(event)" ondrop="stopDrop(event)">
<img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=abb8c8f648a493c832e25a20bd7937e2&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201204%2F13%2F161232b8vbsjjthbh0mty0.jpg" alt="">
</li>
<li draggable="true" id="li3" ondragstart="dragStart(event)" ondrop="stopDrop(event)">
<img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=bbab3059864fa1ce42ff0b714184607f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201510%2F14%2F20151014231057_r8tZm.jpeg" alt="">
</li>
</ul>
<ul id="app2" class="app"
ondragover="dragover(event)"
ondrop="drop(event)"
></ul>
</div>
</body>
</html>
<script>
function stopDrop(ev){
ev.stopPropagation();
return false;
}
// 在滑动的过程中,取消目标元素的默认事件
function dragover(ev){
ev.preventDefault();
}
// 释放元素
function drop(ev){
// 取消元素的默认事件
ev.preventDefault();
//获取源对象的相关信息
let sourceId = ev.dataTransfer.getData('sourceId');
//获取源对象相关的元素,
let sourceElement = document.getElementById(sourceId);
//插入到目标元素中
ev.target.appendChild(sourceElement);
}
//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
console.log("开始拖拽======",ev);
ev.dataTransfer.setData('sourceId',ev.target.parentElement.id)
}
</script>
在上面的例子中,我们使用了内联JS,看起来比较繁琐。因此,下面我们用内嵌JS的方式来处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.container {
width: auto;
height: 400px;
display: flex;
flex-direction: row;
}
.app {
width:200px;
height: 400px;
}
.app li {
width: 100%;
}
.app li img {
width: 100%;
}
#app1 {
background-color: cyan;
}
#app2 {
background-color: orange;
margin-left: 100px;
}
</style>
</head>
<body>
<div class="container">
<ul id="app1"
class="app"
>
<li draggable="true" class="list" id="li1">
<img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620194&di=ce0f0e3feda2ed250b10c8d636010e86&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F4%2F56f62bab021a8.jpg" alt="">
</li>
<li draggable="true" class="list" id="li2" >
<img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=abb8c8f648a493c832e25a20bd7937e2&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201204%2F13%2F161232b8vbsjjthbh0mty0.jpg" alt="">
</li>
<li draggable="true" class="list" id="li3" >
<img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=bbab3059864fa1ce42ff0b714184607f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201510%2F14%2F20151014231057_r8tZm.jpeg" alt="">
</li>
</ul>
<ul id="app2" class="app"></ul>
</div>
</body>
</html>
<script>
let apps = document.getElementsByClassName("app");
let lists = document.getElementsByClassName("list");
for(let i=0,length=apps.length;i<length;i++){
let app = apps[i];
// 在滑动的过程中,取消目标元素的默认事件,允许拖拽内容放下
app.ondragover = function(ev){
ev.preventDefault();
}
app.ondragstart = dragStart;
app.ondrop = drop;
}
//设置所有lists元素开始拖拽
for(let i=0,length=lists.length;i<length;i++){
let li = lists[i];
li.ondragstart = dragStart;
li.ondrop = stopDrop;
}
// 释放元素
function drop(ev){
// 取消元素的默认事件
ev.preventDefault();
//获取源对象的相关信息
let sourceId = ev.dataTransfer.getData('sourceId');
//获取源对象相关的元素,
let sourceElement = document.getElementById(sourceId);
//插入到目标元素中
ev.target.appendChild(sourceElement);
}
//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
console.log("开始拖拽======",ev);
ev.dataTransfer.setData('sourceId',ev.target.parentElement.id)
}
function stopDrop(ev){
ev.stopPropagation();
return false;
}
</script>
在两个元素之间 插入新元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.container {
width: auto;
height: 400px;
display: flex;
flex-direction: row;
}
.app {
width:200px;
height: 400px;
}
.app li {
width: 100%;
}
.app li img {
width: 100%;
}
#app1 {
background-color: cyan;
}
#app2 {
background-color: orange;
margin-left: 100px;
}
</style>
</head>
<body>
<div class="container">
<ul id="app1"
class="app"
>
<li draggable="true" class="list" id="li1">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620194&di=ce0f0e3feda2ed250b10c8d636010e86&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F4%2F56f62bab021a8.jpg" alt="">
</li>
<li draggable="true" class="list" id="li2" >
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=abb8c8f648a493c832e25a20bd7937e2&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201204%2F13%2F161232b8vbsjjthbh0mty0.jpg" alt="">
</li>
<li draggable="true" class="list" id="li3" >
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=bbab3059864fa1ce42ff0b714184607f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201510%2F14%2F20151014231057_r8tZm.jpeg" alt="">
</li>
</ul>
<ul id="app2" class="app"></ul>
</div>
</body>
</html>
<script>
let apps = document.getElementsByClassName("app");
let lists = document.getElementsByClassName("list");
for(let i=0,length=apps.length;i<length;i++){
let app = apps[i];
// 在滑动的过程中,取消目标元素的默认事件,允许拖拽内容放下
app.ondragover = function(ev){
ev.preventDefault();
}
app.ondragstart = dragStart;
app.ondrop = drop;
}
//设置所有lists元素开始拖拽
for(let i=0,length=lists.length;i<length;i++){
let li = lists[i];
li.ondragstart = dragStart;
li.ondrop = dropLi;
}
// 释放元素
function drop(ev){
// 取消元素的默认事件
ev.preventDefault();
//获取源对象的相关信息
let sourceId = ev.dataTransfer.getData('sourceId');
//获取源对象相关的元素,
let sourceElement = document.getElementById(sourceId);
//插入到目标元素中
ev.target.appendChild(sourceElement);
}
//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
ev.dataTransfer.setData('sourceId',ev.target.parentElement.id)
}
function dropLi(ev){
ev.stopPropagation();
//判断li元素放下的时候,目标元素是否是图片,查找该图片的父级元素
let target = ev.target.parentElement;
let parentEle = target.parentElement;
//获取被拖拽的元素
let dragId = ev.dataTransfer.getData("sourceId");
let dragEle = document.getElementById(dragId);
//计算 源对象 拖拽到 目标元素的位置,
/*
如果大于目标元素所在Y轴距离加上元素本身高度的一半,则将 源对象 放到目标元素的后面
小于目标元素所在Y轴距离加上元素本身高度的一半,将 源对象放到目标元素的前面
*/
//获取目标元素的位置
let top = target.offsetTop;
let clientHeight = target.clientHeight;
//获取 鼠标放下的时候,源对象所在的Y轴位置
let clientY = ev.clientY;
let targetTop = top + top / 2;
if(clientY > targetTop){
//放在下面
insertAfter(dragEle,target);
}else{
//放在上面
console.log("放在上面",parentEle);
parentEle.insertBefore(dragEle,target);
}
console.log("距离顶部的距离",top);
}
function stopDrop(ev){
ev.stopPropagation();
return false;
}
// 在后面插入元素
function insertAfter(newEl, targetEl) {
var parentEl = targetEl.parentNode;
if (parentEl.lastChild == targetEl) {
parentEl.appendChild(newEl);
} else {
parentEl.insertBefore(newEl, targetEl.nextSibling);
}
}
</script>
将外部文件拖入到页面中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#container {
width: 300px;
height: 300px;
border: 1px dashed black;
}
.fileList{
width: 100%;
list-style: none;
}
.imgList {
width: 100px;
}
.imgList img {
width: 100%;
}
</style>
</head>
<body>
<form id="container">
<span>请将文件拖拽到这里</span>
<ul class="fileList"></ul>
</form>
</body>
</html>
<script>
var container = document.getElementById('container');
var fileList = document.querySelector(".fileList");
container.addEventListener("dragenter",function(ev){
var ev = ev || window.event;
ev.preventDefault();
ev.stopPropagation();
})
container.addEventListener("dragover",function(ev){
var ev = ev || window.event;
ev.preventDefault();
ev.stopPropagation();
});
container.addEventListener("drop",function(ev){
var ev = ev || window.event;
// console.log(ev.dataTransfer);
var files = ev.dataTransfer.files;
console.log(files);
// 阻止默认事件和冒泡事件,避免浏览器直接打开图片
ev.preventDefault();
ev.stopPropagation();
for(var i=0,length=files.length;i<length;i++){
var file = files[i];
console.log(file);
//将文件转换成dataURL
var fileURL = window.URL.createObjectURL(file);
fileList.innerHTML = `
<li class="imgList">
<img src=${fileURL} alt=${file.name}>
<span>${file.name}</span>
</li>
`
}
})
</script>