📏拖动时,中心参考线📐

写在开头

嘿 😎 各位"陌生人"好鸭❗

五一假期正式结束,距离下个假期端午节还有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-horizontalline-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 将会不断变化)

好了,这样子咱们就完成开头见过的效果了,大功告成。🥳

那么,这节就先这样子啦,下节咱们再来讲讲元素与元素之间的对齐参考线是如何实现的,敬请期待,嘿嘿。👻


至此,本篇文章就写完啦,撒花撒花。

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。

老样子,点赞+评论=你会了,收藏=你精通了。

相关推荐
GoppViper33 分钟前
uniapp中实现<text>文本内容点击可复制或拨打电话
前端·后端·前端框架·uni-app·前端开发
Sam902942 分钟前
【Webpack--007】处理其他资源--视频音频
前端·webpack·音视频
Code成立44 分钟前
HTML5精粹练习第1章博客
前端·html·博客·html5
架构师ZYL1 小时前
node.js+Koa框架+MySQL实现注册登录
前端·javascript·数据库·mysql·node.js
gxhlh2 小时前
React Native防止重复点击
javascript·react native·react.js
miao_zz2 小时前
基于react native的锚点
android·react native·react.js
一只小白菜~2 小时前
实现实时Web应用,使用AJAX轮询、WebSocket、还是SSE呢??
前端·javascript·websocket·sse·ajax轮询
晓翔仔2 小时前
CORS漏洞及其防御措施:保护Web应用免受攻击
前端·网络安全·渗透测试·cors·漏洞修复·应用安全
jingling5552 小时前
后端开发刷题 | 数字字符串转化成IP地址
java·开发语言·javascript·算法
GISer_Jing4 小时前
【前后端】大文件切片上传
前端·spring boot