本文通过拖拽案例,实现“跟随鼠标、边界限定、轨迹回放”三大效果;

完整代码中有详尽注释,故不再进行细致讲解;

对于案例中需要注意的重点或易错点问题,会总结在最后。

效果图(仅演示左、上边界限定)

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>盒子拖拽</title>
<style>
body{
margin: 0;
padding: 0;
}
#box{
width: 100px;
height: 100px;
background: skyblue;
position: absolute;
/* 盒子在页面中的初始位置,可以随意设置 */
left: 200px;
top: 200px;
}
#btn{
display: inline-block;
width: 80px;
height: 30px;
font-size: 16px;
cursor: pointer;
outline: none;
}
</style>
</head>
<body>
<div id="box"><button id="btn">轨迹回放</button></div>
<script>
var box_ele = document.getElementById("box");
// 声明位置数组,用于记录盒子每次移动后的位置
var position_arr = [];
// 获取页面初始宽高,用于限定盒子移动边界
var screen_width = document.body.offsetWidth;
var screen_height = window.innerHeight; // 注意页面高度不能通过 document.body.offsetTop 获取 // 功能1:拖拽
// 设置变量记录鼠标的状态,鼠标按下时为true
var flag = false;
// 鼠标按下准备拖拽,记录鼠标按下时的位置
var mouse_x, mouse_y;
box_ele.addEventListener("mousedown", function(evt){
flag = true;
var e = evt || event;
mouse_x = e.offsetX; // 要以元素做参照物,用offset,不能用client
mouse_y = e.offsetY;
// 将盒子初始位置(盒子元素偏移量)记录在位置数组中
position_arr.push({
x : box_ele.offsetLeft,
y : box_ele.offsetTop
})
})
// 鼠标移动拖拽开始
// 事件绑定在document上,避免因鼠标移动速度太快超出盒子边界时盒子跟不上
document.addEventListener("mousemove", function(evt){
if(flag){
var e = evt || event;
// 声明盒子的位置
var box_left = e.clientX - mouse_x;
var box_top = e.clientY - mouse_y;
// 通过页面初始宽高和盒子宽高计算获得盒子移动的最大值
var move_width_max = screen_width - box_ele.offsetWidth;
var move_height_max = screen_height - box_ele.offsetHeight;
// 分别限定盒子移动的左右上下边界
box_left = box_left <= 0 ? 0 : box_left;
box_left = box_left >= move_width_max ? move_width_max : box_left;
box_top = box_top <= 0 ? 0 : box_top;
box_top = box_top >= move_height_max ? move_height_max : box_top;
// 将数据赋值给盒子从而在页面中渲染
box_ele.style.left = box_left + "px";
box_ele.style.top = box_top + "px";
// 若x或y方向移动距离大于5px,则将移动后的盒子位置记录到位置数组中(避免数组中保存数据过多,消耗性能)
if(box_left >= position_arr[position_arr.length - 1].x + 5 || box_top >= position_arr[position_arr.length - 1].y + 5){
position_arr.push({
x : box_left,
y : box_top
})
} }
}) // 鼠标抬起拖拽停止
box_ele.addEventListener("mouseup", function(){
flag = false;
}) // 功能2:回放
var btn_ele = document.getElementById("btn");
var timer;
btn_ele.addEventListener("click", function(){
// 原思路:通过for循环遍历位置数组中的每一个位置
// 由于for循环执行太快,故使用定时器
timer = setInterval(function(){
// 每次取出位置数组中的最后一个元素位置
var last_position = position_arr.pop();
box_ele.style.left = last_position.x + "px";
box_ele.style.top = last_position.y + "px";
// 当移动到最后一个位置(即位置数组中数据为空)时,关闭定时器
if(position_arr.length === 0){
clearInterval(timer);
}
}, 50)
})
</script>
</body>
</html>

注意点

1、鼠标拖拽过程中的盒子位置需要通过 鼠标位置 - 初始时鼠标相对于元素位置 获取,即

box_left = e.clientX - mouse_x

box_top = e.clientY - mouse_y;

否则盒子会出现在鼠标的右下方。

2、初始的页面高度不能通过 document.body.offsetTop 获取,需要用 window.innerHeight

3、限制鼠标移动边界时,宽高方向的最大值需要通过 初始页面宽高 - 盒子宽高 获取,即

move_width_max = screen_width - box_ele.offsetWidth;

move_height_max = screen_height - box_ele.offsetHeight;

4、轨迹回放时,目标是位置数组中从后往前依次取出元素,最好的办法就是使用 pop()

5、注意定时器的关闭条件。position_arr.length === 0

Javascript之盒子拖拽(跟随鼠标、边界限定、轨迹回放)的更多相关文章

  1. 每天一个JavaScript实例-html5拖拽

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  2. day25—JavaScript实现文件拖拽上传案例实践

    转行学开发,代码100天——2018-04-10 今天记录一个利用JavaScript实现文件拖拽上传到浏览器,后天将文件打开的小案例. 基本功能:1点击添加文件 2 文件拖拽添加 html: < ...

  3. day23—JavaScript实现DIV盒子拖拽(原生方式)

    转行学开发,代码100天——2018-04-08 <!doctype html> <html> <head> <meta charset="utf- ...

  4. JavaScript动画-模拟拖拽

    模拟拖拽的原理: x1等于div.offsetLeft y1等于div.offsetTop x2等于ev.clientX(ev表示event事件) y2等于ev.clientY 当我们在方块上按下鼠标 ...

  5. QTGraphics-View拖拽以及鼠标指针操作

    因为QGraphicsView继承自QWidget,它也提供了像QWidget那样的拖拽功能. 另外,为了方便,Graphics View框架也为场景以及每个item提供拖拽支持.当视图接收到拖拽事件 ...

  6. JavaScript实现图片拖拽、粘贴上传

    前些日子为老婆做了一个web管理商品的工具,因为商品的图片比较多并且还需要剪裁图,为了上传图片方便加了一个拖拽.粘贴上传的功能. 我已经把代码整理出来放到GitHub上了,有兴趣的朋友可以下来玩玩. ...

  7. javascript实现的拖拽回放

    这个功能很简单,直接贴代码啊: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  8. 超级简单的利用javascript实现文件拖拽事件

    1.效果图: 2.源码 <%@ page contentType="text/html;charset=UTF-8" language="java" %& ...

  9. JavaScript 面向对象的拖拽

    一.body <div id="box"></div> 二.css <style> #box { position: abaolute; top ...

随机推荐

  1. Autotestplat体验中心

    web端 移动端 可戳[阅读原文]进行体验

  2. 解决sendmail发送邮件慢的问题

    sendmail默认会先监听本机的邮件服务,如果本机邮件服务访问不了,在访问其他的邮件服务器 自己测试将本机主机名(通过hostname命令查看)从/etc/hosts中删除,发送邮件的速度就非常快了 ...

  3. VM安装Linux Centos7.0虚拟机

    一.准备工作 1.安装VMware 官网https://www.vmware.com/cn.html 2.准备centos7的镜像文件 官网下载链接:http://isoredirect.centos ...

  4. ORB-SLAM2 运行 —— ROS + Android 手机摄像头

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12404730.html 本文要点: ROS 配置安装 解决 sud ...

  5. clientWidth offsetWidth等视窗尺寸

    clientWidth和offsetWidth clientWidth 是一个只读属性,返回元素的内部宽度,该属性包括内边距,但不包括垂直滚动条(如果有).边框和外边距. offsetWidth 是一 ...

  6. 容器内init进程方案

    背景 进程标识符 (PID) 是Linux 内核为每个进程提供的唯一标识符.熟悉docker的同学都知道, 所有的进程 PID都属于某一个PID namespaces, 也就是说容器具有一组自己的 P ...

  7. Generator的异步编程

    对比下常用的异步处理的方案: 1,回调 我们常说的 “回调地狱”,就是多个异步操作时候,代码多重嵌套,异步之前形成强耦合,如果修改一处,其他地方也是跟着修改.(callback hell). 2,pr ...

  8. 【.net core】电商平台升级之微服务架构应用实战

    一.前言 这篇文章本来是继续分享IdentityServer4 的相关文章,由于之前有博友问我关于微服务相关的问题,我就先跳过IdentityServer4的分享,进行微服务相关的技术学习和分享.微服 ...

  9. (转)协议森林06 瑞士军刀 (ICMP协议)

    协议森林06 瑞士军刀 (ICMP协议) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 到现在为止,我们讲解了网络层中最重要的I ...

  10. 将config从内部移动到外部 3部曲

    1 创建 public/config.js /* eslint-disable no-shadow-restricted-names */ // eslint-disable-next-line no ...