HTML5提供专门的拖拽与拖放的API,以后实现这类效果就不必乱折腾了。但是,考虑到Opera浏览器似乎对此不感冒,在通用性上有待商榷,所以这里也就简单说一说。
兼容性: 不支持IE9
segmentfault.com/a/119000001… www.cnblogs.com/yehuisir/p/…
1. draggable 属性:就是标签元素要设置draggable=true,否则不会有效果,例如
<div title="拖拽我" draggable="true">列表1</div>
拖放是 HTML5 中非常常见的功能。
注意: 为了让元素可拖动,需要使用 HTML5 draggable 属性。
提示: 链接和图片默认是可拖动的,不需要 draggable 属性。
在拖放的过程中会触发以下事件:
2. 在拖动目标上触发事件 (源元素) ,作用在被拖拽元素上:
ondragstart - 用户开始拖动元素时触发 ondrag - 元素正在拖动时触发 ondragend - 用户完成元素拖动后触发
3. 释放目标时触发的事件,作用在目标元素上:
- 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" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>拖动事件讲解</title>
<style>
.demo {
list-style: none;
background-color: aqua;
height: 30px;
width: 150px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<!-- 图片和链接默认可以拖动 -->
<!-- 被拖拽的源对象 -->
<div class="demo" id="demo" draggable="true">测试</div>
<!-- 目标对象,容器 -->
<div
id="wrapper"
style="width: 300px; height: 400px; border: 1px solid #000"
></div>
<script>
//找到被拖拽的源对象
var demo = document.getElementById("demo");
// 目标对象,容器
var wrapper = document.getElementById("wrapper");
demo.ondragstart = function () {
console.log("用户开始拖动元素的时候触发");
};
demo.ondrag = function () {
console.log("正在拖动时候触发");
};
demo.ondragend = function () {
console.log("结束拖动时候触发");
};
wrapper.addEventListener("dragenter", function () {
console.log("dragenter 进入其容器范围内触发");
});
wrapper.addEventListener("dragover", function (ev) {
ev.preventDefault();
console.log("dragover 被拖动的对象在另一对象容器范围内拖动");
});
wrapper.addEventListener("dragleave", function () {
console.log("dragleave 拖动的对象离开其容器范围内时触发");
});
wrapper.addEventListener("drop", function () {
console.log("drop 释放鼠标键时触发");
});
</script>
</body>
</html>
4. Event.preventDefault() 方法:
阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。
另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。
DataTransfer
对象:拖拽对象用来传递的媒介,使用一般为Event.dataTransfer。
DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据。它可以保存一项或多项数据,这些数据项可以是一种或者多种数据类型。 dataTransfer对象提供了一些方法用于在源元素与目标元素中共享数据 方法
-
setData(type,data):用于声明所发送的数据与类型 etData(type): 返回指定type的数据
- clearData(type):删除指定类型的数据
event.dataTransfer.setDragImage(p_w_picpath,x,y);
- setDragImage方法用于在拖放操作过程中,修改鼠标指针所指向的图像
5. 使用案例
- 通过拖拽分组
<!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>通过拖拽分组的小例子</title>
<style>
body {
display: flex;
justify-content: space-around;
}
.box1,
.box2 {
padding: 10px;
width: 300px;
border: 1px solid #000;
min-height: 50px;
}
.box2 {
max-height: 500px;
}
.demo {
list-style: none;
background-color: aqua;
margin: 10px;
height: 30px;
padding-left: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<div>
<h1>组一:知识列表</h1>
<ul class="box1" id="box1Out">
<li class="demo" draggable="true">1. HTML5+CSS3</li>
<li class="demo" draggable="true">2. WEBPACK</li>
<li class="demo" draggable="true">3. VUE</li>
<li class="demo" draggable="true">4. React</li>
<li class="demo" draggable="true">5. ES5/ES6</li>
</ul>
</div>
<div>
<h1>组二:你喜欢的</h1>
<ul class="box2" id="boxFrame"></ul>
</div>
<script>
//被拖的对象
var demolist = document.querySelectorAll(".demo");
// 当前正在拖的是哪个li
var dragDom = null;
for (let i = 0, len = demolist.length; i < len; i++) {
demolist[i].ondragstart = function (ev) {
// console.log(this);
// console.log(demolist[i]);
dragDom = this;
};
}
//目标对象, 容器
var boxFrame = document.getElementById("boxFrame");
// dragover drap
boxFrame.ondragover = function (ev) {
ev.preventDefault();
};
boxFrame.ondrop = function () {
console.log(dragDom);
this.appendChild(dragDom);
//被拖拽的对象插入到目标容器
};
</script>
</body>
</html>
- 拖拽删除
<!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>
.dustbin {
width: 100px;
height: 260px;
line-height: 1.4;
background-color: gray;
font-size: 36px;
font-family: "微软雅黑", "Yahei Mono";
text-align: center;
text-shadow: -1px -1px #bbb;
float: left;
}
.dragbox {
width: 500px;
padding-left: 20px;
float: left;
}
.draglist {
padding: 10px;
margin-bottom: 5px;
border: 2px dashed #ccc;
background-color: #eee;
cursor: move;
}
.dragremind {
padding-top: 2em;
clear: both;
}
</style>
</head>
<body>
<div class="dustbin"><br />垃<br />圾<br />箱</div>
<div class="dragbox">
<div class="draglist" title="拖拽我" draggable="true">列表1</div>
<div class="draglist" title="拖拽我" draggable="true">列表2</div>
<div class="draglist" title="拖拽我" draggable="true">列表3</div>
<div class="draglist" title="拖拽我" draggable="true">列表4</div>
<div class="draglist" title="拖拽我" draggable="true">列表5</div>
<div class="draglist" title="拖拽我" draggable="true">列表6</div>
</div>
<div class="dragremind"></div>
<script>
// 源对象, 被拖拽的对象
var draglists = document.querySelectorAll(".draglist");
//目标对象
var dustbin = document.querySelector(".dustbin");
var eleDom = null; //当前被拖拽的对象
for (let i = 0, len = draglists.length; i < len; i++) {
draglists[i].ondragstart = function (ev) {
//开始拖拽
ev.dataTransfer.setData("text", ev.target.innerHTML);
var imgDom = new Image();
imgDom.src = "./imgs/play-btn.png";
ev.dataTransfer.setDragImage(ev.target, 0, 0);
eleDom = this;
};
// 没有进到目标对象
draglists[i].ondragend = function (ev) {
//清除数据
ev.dataTransfer.clearData("text");
eleDom = null;
};
//目标对象
dustbin.ondragenter = function (ev) {
// 当被鼠标拖动的对象进入其容器范围内时触发此事件
this.style.color = "#fff";
};
dustbin.ondragover = function (ev) {
ev.preventDefault();
};
dustbin.ondrop = function (ev) {
if (eleDom) {
var info = ev.dataTransfer.getData("text");
document.querySelector(".dragremind").innerHTML =
info + "被扔进了垃圾箱";
eleDom.remove();
// eleDom.preventNode.removeChild(eleDom); //复杂
}
};
}
</script>
</body>
</html>
- 拖拽上传文件
<!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>文件拖拽上传并以base64传给后台</title>
<style>
ul,
li {
list-style-type: none;
margin: 0;
padding: 0;
}
.out-main-top {
height: auto;
overflow: auto;
display: flex;
justify-content: flex-start;
}
.out-main-top button {
padding: 10px 40px;
font-weight: bold;
font-size: 21px;
height: 52px;
margin-left: 30px;
vertical-align: middle;
margin-top: 60px;
}
.canvas-img {
margin-top: 20px;
clear: both;
}
.canvas-img li {
width: 150px;
height: 150px;
position: relative;
border: 1px solid #ccc;
cursor: pointer;
float: left;
margin-right: 10px;
overflow: hidden;
}
.canvas-img li img {
width: 90%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.canvas-img li .close {
position: absolute;
right: 4px;
top: 1px;
font-style: normal;
font-size: 12px;
color: #666;
}
.drag-box {
width: 250px;
height: 200px;
border: 1px dashed #ccc;
margin-left: 20px;
color: #ccc;
font-size: 15px;
text-align: center;
padding-top: 90px;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="out-main-top">
<div id="dropbox" class="drag-box">或者将文件拖到此处</div>
<button type="button" onclick="uploadFileNow()">上传</button>
</div>
<ul id="canvasImg" class="canvas-img"></ul>
<script>
var canvasImg = document.getElementById("canvasImg");
//目标对象
var dropbox = document.getElementById("dropbox");
var allBaseImg = []; //需要给到后台的图片数据
var AllowImgFileSize = 1024 * 400; //上传图片最大值(单位字节)超过400K上传失败
dropbox.addEventListener("dragover", function (ev) {
ev.preventDefault();
});
dropbox.addEventListener("drop", function (ev) {
console.log(ev);
// 通知web浏览器不要执行与事件关联的默认行为
ev.preventDefault();
console.log("files", ev.dataTransfer.files);
var dtfiles = ev.dataTransfer.files;
//转化成base64
transferDataToBase64(dtfiles);
});
function transferDataToBase64(files) {
for (let i = 0, len = files.length; i < len; i++) {
var file = files[i];
var reader = new FileReader();
reader.readAsDataURL(file); //转化为base64的格式 ,异步
reader.onload = function (ev) {
var base64Img = ev.target.result;
var index = allBaseImg.indexOf(base64Img); //includes
if (index != -1) {
return;
}
//图片大小是否符合
if (base64Img.length > AllowImgFileSize) {
alert("图片上传失败,需要小于400K");
return;
}
var str = `<li> <img src='${base64Img}'> <i class='close'>X</i></li>`;
canvasImg.innerHTML += str;
allBaseImg.push(base64Img);
};
}
}
//监听缩略图 的删除事件 ,事件委托
canvasImg.addEventListener("click", function (ev) {
var target = ev.target;
if (target.className == "close") {
var thisbase = target.previousElementSibling; //方式一
var sindex = allBaseImg.indexOf(thisbase);
allBaseImg.splice(sindex, 1); //更新数据
//删除缩略图
target.parentElement.remove();
}
});
//需要调接口,给图片数据到后端服务
function uploadFileNow() {
console.log(allBaseImg);
console.log("调接口");
}
</script>
</body>
</html>
- 拖拽排序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>
ul {
list-style: none;
margin: 200px;
font-size: 0;
}
.ele {
font-size: 16px;
width: 100px;
height: 40px;
border: 1px solid #999;
background: #ea6e59;
margin: 2px 0;
border-radius: 10px;
padding-left: 10px;
color: white;
cursor: move;
}
</style>
<body>
<ul id="container">
<li class="ele" draggable="true">1</li>
<li class="ele" draggable="true">2</li>
<li class="ele" draggable="true">3</li>
<li class="ele" draggable="true">4</li>
<li class="ele" draggable="true">5</li>
<li class="ele" draggable="true">6</li>
<li class="ele" draggable="true">7</li>
<li class="ele" draggable="true">8</li>
</ul>
</body>
<script>
var node = document.querySelector("#container");
var draging = null;
//使用事件委托,将li的事件委托给ul
node.ondragstart = function (event) {
//firefox设置了setData后元素才能拖动!!!!
event.dataTransfer.setData("te", event.target.innerText); //不能使用text,firefox会打开新tab
draging = event.target;
};
node.ondragover = function (event) {
event.preventDefault();
var target = event.target;
//因为dragover会发生在ul上,所以要判断是不是li
if (target.nodeName === "LI" && target !== draging) {
//_index是实现的获取index
if (_index(draging) < _index(target)) {
target.parentNode.insertBefore(draging, target.nextSibling);
} else {
target.parentNode.insertBefore(draging, target);
}
}
};
function _index(el) {
var index = 0;
if (!el || !el.parentNode) {
return -1;
}
while (el && (el = el.previousElementSibling)) {
index++;
}
return index;
}
</script>
</html>