通过10分钟时间学习HTML5中的拖拽功能,让用户交互体验更加流畅。
今天给大家带来HTML5中新增的属性来实现拖拽功能,先来看看实现后的效果,如下:
在该例子中,可以将任意一个元素进行拖拽到另一个元素上进行替换。
前言
HTML5新增了一个可拖拽的属性,即draggable,属性draggable 设置为 "true",这个元素变成可拖拽的,并且该属性是可以设置在任意元素上,包括图像和链接,在拖拽时为该元素增加dragstart监听事件,在结束拖拽时添加ondragend监听事件。
基础结构
HTML部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML5拖拽实现</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="list">
<div class="list-item" draggable="true" style="--color: #b01a01">
<img src="https://picsum.photos/id/237/200" alt="">
<span>1</span>
</div>
<div class="list-item" draggable="true" style="--color: #70d265">
<img src="https://picsum.photos/seed/picsum/200" alt="">
<span>2</span>
</div>
<div class="list-item" draggable="true" style="--color: #f0e941">
<img src="https://picsum.photos/200" alt="">
<span>3</span>
</div>
<div class="list-item" draggable="true" style="--color: #da8218">
<img src="https://picsum.photos/200?grayscale" alt="">
<span>4</span>
</div>
<div class="list-item" draggable="true" style="--color: #f1e867">
<img src="https://picsum.photos/200?blur=2" alt="">
<span>5</span>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
CSS部分
* {
margin: 0;
padding: 0;
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #333;
}
.list-item {
width: 400px;
height: 70px;
background-color: var(--color);
border-radius: 8px;
margin: 15px 0;
padding-left: 20px;
display: flex;
align-items: center;
/* 光标变移动图标 */
cursor: move;
}
.list-item img {
width: 50px;
height: 50px;
object-fit: cover;
object-position: top;
margin-right: 20px;
}
.list-item span {
color: #fff;
font-size: 22px;
letter-spacing: 2px;
text-shadow: 1px 1px 2px rgba(0, 0, 0, .5);
}
/* 接下来添加拖拽时的样式 */
.list-item.moving{
background-color: transparent;
border: 2px dashed #ccc;
}
.list-item.moving img,
.list-item.moving span {
display: none;
}
定义了HTML和CSS样式后,网页效果图如下。
核心部分
核心代码如下:
const list = document.querySelector(".list");
const item = document.querySelectorAll(".list-item");
// 判断房前拖动的是哪个元素
let sourceNode;
// 开始拖动的事件
list.ondragstart = (e) => {
sourceNode = e.target;
// 记录起始位置
record(item);
// 添加moving样式
setTimeout(() => {
e.target.classList.add("moving");
}, 0);
// 设置被拖动元素允许移动到新的位置
e.dataTransfer.effectAllowed = "move";
};
// 在元素正在拖动到放置目标时触发
list.ondragover = (e) => {
e.preventDefault();
};
// 元素在拖拽过程中
list.ondragenter = (e) => {
e.preventDefault();
if (e.target === list || e.target === sourceNode) {
return false;
}
const children = [...list.children];
const sourceIndex = children.indexOf(sourceNode);
const targetIndex = children.indexOf(e.target);
if (sourceIndex < targetIndex) {
// insertBefore(要插入的节点,在谁前面)
// 下方
list.insertBefore(sourceNode, e.target.nextElementSibling);
record([sourceNode]);
} else {
// 上方
list.insertBefore(sourceNode, e.target);
record([sourceNode]);
}
last([e.target, sourceNode]);
};
// 拖动结束时取消虚线
list.ondragend = (e) => {
e.target.classList.remove("moving");
};
// 记录起始位置
function record(eleAll) {
for (let i = 0; i < eleAll.length; i++) {
const { top, left } = eleAll[i].getBoundingClientRect();
eleAll[i]._top = top;
eleAll[i]._left = left;
}
}
// 记录最后的位置,并执行动画
function last(eleAll) {
for (let i = 0; i < eleAll.length; i++) {
const dom = eleAll[i];
const { top, left } = dom.getBoundingClientRect();
if (dom._left) {
dom.style.transform = `translate3d(${dom._left - left}px, ${
dom._top - top
}px, 0px)`;
let rafid = requestAnimationFrame(function () {
dom.style.transition = "transform 0.3s ease-out";
dom.style.transform = "none";
});
dom.addEventListener("transitionend", () => {
dom.style.transition = "none";
cancelAnimationFrame(rafid);
});
}
}
}
总结
通过上述例子,想要实现拖拽需要做的以下几点:
- 在节点声明能够拖拽,设置
draggable属性为true - 监听
ondragstart事件,用于记录拖拽前的起始位置 - 监听
ondragenter事件,用于记录拖拽过程中的位置变化 - 监听
ondragend事件,用于记录拖拽后的终点位置