写在开头
嘿 😎 各位"陌生人"好鸭❗
五一假期正式结束,距离下个假期端午节还有40天左右,加油,假期正在向我们招手!
记录一下🎥🎥🎥:
感觉这应该是最"丧"的一个五一假期了吧,天公不作美,每天基本都在下雨☔,俺假期前洗的鞋子到现在还没完全干呢。😓
在这五天里,总的来说小编就干三件事情,租房子、相亲记、看综艺。
- 租房子:陪同来广州工作的朋友冒雨去找房子,唉,感觉找房子比找工作还难啊,真累人。😣
- 相亲记:Em...家里介绍的,但,黄了😆,She deserves someone better。
- 看综艺:朋友安利 "花儿与少年好友记"、"小熊花园",其实我不太爱看的,但还是看了亿点点,呃...收回前话,挺好笑,很开心。😁😁😁 还有,看了部美剧"无耻之徒",很难评,但也挺好看得。
好❗就这样,回到正题,本文要分享的效果如下,请诸君按需食用。
哦😶,还有,阅读本文之前,建议你可以稍微看看小编的另一篇 拖动❓元素拖动、列表拖动、表格拖动(列与行)🍊🍊🍊 的文章,能更好的理解,当然,不看问题也不大啦,小编会标上详情注释的。🤡
布局与样式
咱们先来整一下布局与样式,很简单直接贴代码:
html
<!DOCTYPE html>
<html>
<head>
<style>
.container {
width: 600px;
height: 400px;
border: 1px solid #ccc;
position: relative;
}
.line-horizontal::before {
content: '';
position: absolute;
top: 50%;
height: 2px;
width: 100%;
transform: translateY(-50%);
background-color: red;
}
.line-vertical::after {
content: '';
position: absolute;
left: 50%;
width: 2px;
height: 100%;
transform: translateX(-50%);
background-color: red;
}
.draggable {
width: 100px;
height: 100px;
background: #1e80ff;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
z-index: 1;
cursor: move;
user-select: none;
touch-action: none;
}
</style>
</head>
<body>
<div class="container line-horizontal line-vertical">
<div class="draggable">橙某人</div>
</div>
</body>
</html>
大概是这样子的效果:
(丑?不要在意这些细节🙊)
在上述代码中,咱们可以看到参考线是通过两个类 line-horizontal
和 line-vertical
进行控制的。为了让大家先睹为快,我已预先添加了这些样式。接下来,我们将使用 JS
来动态控制这些参考线的显示和隐藏,这里你应该能猜到,如何检测元素是否已经拖动到参考线上了 这将是重点。💀
将元素变成可拖动元素
这个功能其实就可以看看这篇文件 拖动❓元素拖动、列表拖动、表格拖动(列与行)🍊🍊🍊 ,里面有详细的介绍。
但是呢,这里小编准备要换一种方式来完成这个功能,要不写重复功能多没意思😋,你可以两种都瞧瞧,感觉一下有什么不同囖。
且看:
html
<script>
document.addEventListener('DOMContentLoaded', () => {
const draggable = document.querySelector('.draggable');
draggable.addEventListener('mousedown', mouseDownHandler);
// 记录拖动元素的偏移量
let dx = 0;
let dy = 0;
// 记录鼠标按下的位置
let startPoint = {
x: 0,
y: 0,
};
function mouseDownHandler(e) {
// 为什么要减掉偏移量操作?
startPoint = {
x: e.clientX - dx,
y: e.clientY - dy,
};
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
function mouseMoveHandler(e) {
// 计算移动的偏移量
dx = e.clientX - startPoint.x;
dy = e.clientY - startPoint.y;
// 通过偏移量来使元素进行移动
draggable.style.transform = `translate(${dx}px, ${dy}px)`;
};
function mouseUpHandler() {
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
});
</script>
不难哈,就直接获取拖动元素,注册监听事件,通过计算偏移量,赋值给元素的 translate
属性就能控制元素进行拖动了。
为什么需要在
mouseDownHandler
进行e.clientX - dx
操作?因为
clientX/Y
:提供了鼠标指针相对于浏览器视口(即当前可见的页面部分)左上角的水平坐标。不论页面是否滚动,clientX
的值都是相对于视口的。如果不去减少"上一次"的偏移量的话,你的"下一次"操作拖动元素都会回到原本的位置再开始移动。
拖动边界处理
通过上面步骤的处理,元素现在已经具备了拖动的功能。不过,目前它可以在屏幕上自由移动,而咱们应期望将其限制在父容器(.container
)的范围内。这样的约束不仅让用户的交互更加直观,还能有效提升整体的用户体验。
那么,如何将元素约束在父容器中呢❓
咱们需要计算它在每个方向上的最大移动距离,最小就不用计算了,由于我们使用 translate
属性来实现元素的偏移,最小移动距离自然就是0。至于最大移动距离,可以通过父容器的宽度和高度减去元素自身的宽度和高度来得出,这样,我们就能确保元素在拖动时不会超出父容器的边界。
javascript
function mouseMoveHandler(e) {
// 保留实际偏移量
const dxTemp = e.clientX - startPoint.x;
const dyTemp = e.clientY - startPoint.y;
// 计算最大移动距离
const containerRect = container.getBoundingClientRect();
const draggableRect = draggable.getBoundingClientRect();
const maxX = containerRect.width - draggableRect.width;
const maxY = containerRect.height - draggableRect.height;
// 将实际偏移量限制在某个范围内容
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
dx = clamp(dxTemp, 0, maxX);
dy = clamp(dyTemp, 0, maxY);
draggable.style.transform = `translate(${dx}px, ${dy}px)`;
};
这下它就跑不了了,嘿嘿。😋
检测元素是否在参考线上
接下来呢,就是最关键一步了,怎么检测元素拖动到中心参考线上了呢❓
咱们先来看看具体代码:
javascript
function mouseMoveHandler(e) {
...
// 检测元素是否在参考线上
const threshold = 5;
const containerCenterX = containerRect.left + containerRect.width / 2;
const containerCenterY = containerRect.top + containerRect.height / 2;
const draggableCenterX = draggableRect.left + draggableRect.width / 2;
const draggableCenterY = draggableRect.top + draggableRect.height / 2;
const verticalLineActive = Math.abs(draggableCenterX - containerCenterX) <= threshold;
const horizontalLineActive = Math.abs(draggableCenterY - containerCenterY) <= threshold;
if (verticalLineActive) {
container.classList.add('line-vertical');
}else {
container.classList.remove('line-vertical');
}
if (horizontalLineActive) {
container.classList.add('line-horizontal');
}else {
container.classList.remove('line-horizontal');
}
}
增加了几行代码,threshold
用来控制拖动元素是否在与水平或垂直中心参考线的一定距离内。
通过分别计算父容器和拖动元素的各自中心线距离,两者一比较就能知道两个中心线是否在一条直线上,也就能检测出拖动元素是否在中心参考线上了。
可以对照瞧瞧下图:
(在拖动过程中,draggableRect.left/draggableRect.top
将会不断变化)
好了,这样子咱们就完成开头见过的效果了,大功告成。🥳
那么,这节就先这样子啦,下节咱们再来讲讲元素与元素之间的对齐参考线是如何实现的,敬请期待,嘿嘿。👻
至此,本篇文章就写完啦,撒花撒花。
希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。