js实现盒子拖拽动画效果

yizhihongxing

实现盒子拖拽动画效果需要以下步骤:

1. 为拖拽目标元素绑定事件监听器

首先需要为需要拖拽的目标元素添加事件监听器,通常是mousedown事件或者touchstart事件。

let target = document.getElementById('drag-target');
target.addEventListener('mousedown', dragStart);
target.addEventListener('touchstart', dragStart);

其中dragStart函数是拖拽开始的处理函数,我们接下来会讲到。

2. 实现拖拽功能

当用户开始拖拽目标元素时,我们需要对鼠标或手指的移动进行监听,并实时更新目标元素的位置,以实现拖拽效果。我们需要给目标元素的父元素绑定事件监听器,监听mousemove事件或者touchmove事件,并在事件处理函数中更新目标元素的位置。

let container = document.getElementById('drag-container');
container.addEventListener('mousemove', dragging);
container.addEventListener('touchmove', dragging);

其中dragging函数是拖拽中的处理函数,我们接下来会讲到。

在处理函数中,我们通过事件对象获取鼠标或手指的位置,然后计算出目标元素相对于父元素的位置,再设置目标元素的样式即可。

function dragging(e) {
  e.preventDefault(); // 防止默认行为(比如滚动)
  let offsetX, offsetY;
  if (e.type === 'mousemove') {
    offsetX = e.clientX - container.offsetLeft;
    offsetY = e.clientY - container.offsetTop;
  } else if (e.type === 'touchmove') {
    offsetX = e.touches[0].clientX - container.offsetLeft;
    offsetY = e.touches[0].clientY - container.offsetTop;
  }
  target.style.left = offsetX + 'px';
  target.style.top = offsetY + 'px';
}

需要注意的是,在触摸设备上,我们需要获取touches数组中第一个触摸点的位置。

3. 实现拖拽动画效果

在上一步拖动中,我们已经可以实现目标元素的拖动。接下来我们需要添加缓动效果,使目标元素在松开鼠标或手指时能够平稳地移动到目标位置。我们可以使用requestAnimationFrame函数来实现动画效果。

首先,我们需要在mousedowntouchstart事件中记录目标元素的初始位置和事件发生的时间。

function dragStart(e) {
  let offsetX, offsetY;
  if (e.type === 'mousedown') {
    offsetX = e.clientX - target.offsetLeft;
    offsetY = e.clientY - target.offsetTop;
  } else if (e.type === 'touchstart') {
    offsetX = e.touches[0].clientX - target.offsetLeft;
    offsetY = e.touches[0].clientY - target.offsetTop;
  }
  let startTime = Date.now();
  let startPos = {x: target.offsetLeft, y: target.offsetTop};
  // 在这里保存初始位置和时间
}

然后,我们可以在mousemovetouchmove事件中更新目标元素的位置,并计算出目标位置和当前位置之间的距离和时间间隔,以便计算缓动效果。

function dragging(e) {
  // 在这里更新目标元素的位置
  let offsetX, offsetY;
  if (e.type === 'mousemove') {
    offsetX = e.clientX - container.offsetLeft;
    offsetY = e.clientY - container.offsetTop;
  } else if (e.type === 'touchmove') {
    offsetX = e.touches[0].clientX - container.offsetLeft;
    offsetY = e.touches[0].clientY - container.offsetTop;
  }
  target.style.left = offsetX + 'px';
  target.style.top = offsetY + 'px';

  // 在这里计算移动距离和时间间隔
  let distance = Math.sqrt(Math.pow(offsetX-startPos.x,2) + Math.pow(offsetY-startPos.y,2));
  let duration = Date.now() - startTime;
}

最后,在mouseuptouchend事件中,我们可以根据移动距离和时间间隔计算出缓动效果的参数(速度和加速度),然后使用requestAnimationFrame函数实现动画效果。

function dragEnd(e) {
  // 在这里计算速度和加速度
  let velocity = distance / duration;
  let direction = Math.atan2(offsetY-startPos.y, offsetX-startPos.x);
  let acceleration = velocity * 10;
  let startX = target.offsetLeft, startY = target.offsetTop;

  // 定义动画函数
  function animate() {
    let elapsed = Date.now() - startTime;
    let dx = startX + velocity * elapsed * Math.cos(direction);
    let dy = startY + velocity * elapsed * Math.sin(direction) + acceleration * Math.pow(elapsed, 2) / 2;
    // 判断动画是否结束,如果未结束继续更新位置,否则停止动画
    if (elapsed < duration) {
      target.style.left = dx + 'px';
      target.style.top = dy + 'px';
      requestAnimationFrame(animate);
    } else {
      target.style.left = startX + distance * Math.cos(direction) + 'px';
      target.style.top = startY + distance * Math.sin(direction) + 'px';
    }
  }
  animate();
}

这样,我们就实现了盒子拖拽动画效果。下面给出两个示例,分别实现了鼠标和触摸设备的拖拽效果。

示例 1:鼠标拖拽

<div id="drag-container" style="position: relative;width: 300px;height: 300px;background-color: #eee;">
  <div id="drag-target" style="position: absolute;width: 50px;height: 50px;background-color: red;"></div>
</div>

<script>
let target = document.getElementById('drag-target');
let container = document.getElementById('drag-container');
let startPos, startTime, distance, duration;

target.addEventListener('mousedown', dragStart);
container.addEventListener('mousemove', dragging);
container.addEventListener('mouseup', dragEnd);

function dragStart(e) {
  let offsetX = e.clientX - target.offsetLeft;
  let offsetY = e.clientY - target.offsetTop;
  startTime = Date.now();
  startPos = {x: target.offsetLeft, y: target.offsetTop};
}

function dragging(e) {
  e.preventDefault();
  let offsetX = e.clientX - container.offsetLeft;
  let offsetY = e.clientY - container.offsetTop;
  target.style.left = offsetX + 'px';
  target.style.top = offsetY + 'px';
  distance = Math.sqrt(Math.pow(offsetX-startPos.x,2) + Math.pow(offsetY-startPos.y,2));
  duration = Date.now() - startTime;
}

function dragEnd(e) {
  let velocity = distance / duration;
  let direction = Math.atan2(offsetY-startPos.y, offsetX-startPos.x);
  let acceleration = velocity * 10;
  let startX = target.offsetLeft, startY = target.offsetTop;

  function animate() {
    let elapsed = Date.now() - startTime;
    let dx = startX + velocity * elapsed * Math.cos(direction);
    let dy = startY + velocity * elapsed * Math.sin(direction) + acceleration * Math.pow(elapsed, 2) / 2;
    if (elapsed < duration) {
      target.style.left = dx + 'px';
      target.style.top = dy + 'px';
      requestAnimationFrame(animate);
    } else {
      target.style.left = startX + distance * Math.cos(direction) + 'px';
      target.style.top = startY + distance * Math.sin(direction) + 'px';
    }
  }
  animate();
}
</script>

示例 2:触摸设备拖拽

<div id="drag-container" style="position: relative;width: 300px;height: 300px;background-color: #eee;">
  <div id="drag-target" style="position: absolute;width: 50px;height: 50px;background-color: red;"></div>
</div>

<script>
let target = document.getElementById('drag-target');
let container = document.getElementById('drag-container');
let startPos, startTime, distance, duration;

target.addEventListener('touchstart', dragStart);
container.addEventListener('touchmove', dragging);
container.addEventListener('touchend', dragEnd);

function dragStart(e) {
  e.preventDefault();
  let offsetX = e.touches[0].clientX - target.offsetLeft;
  let offsetY = e.touches[0].clientY - target.offsetTop;
  startTime = Date.now();
  startPos = {x: target.offsetLeft, y: target.offsetTop};
}

function dragging(e) {
  e.preventDefault();
  let offsetX = e.touches[0].clientX - container.offsetLeft;
  let offsetY = e.touches[0].clientY - container.offsetTop;
  target.style.left = offsetX + 'px';
  target.style.top = offsetY + 'px';
  distance = Math.sqrt(Math.pow(offsetX-startPos.x,2) + Math.pow(offsetY-startPos.y,2));
  duration = Date.now() - startTime;
}

function dragEnd(e) {
  let velocity = distance / duration;
  let direction = Math.atan2(offsetY-startPos.y, offsetX-startPos.x);
  let acceleration = velocity * 10;
  let startX = target.offsetLeft, startY = target.offsetTop;

  function animate() {
    let elapsed = Date.now() - startTime;
    let dx = startX + velocity * elapsed * Math.cos(direction);
    let dy = startY + velocity * elapsed * Math.sin(direction) + acceleration * Math.pow(elapsed, 2) / 2;
    if (elapsed < duration) {
      target.style.left = dx + 'px';
      target.style.top = dy + 'px';
      requestAnimationFrame(animate);
    } else {
      target.style.left = startX + distance * Math.cos(direction) + 'px';
      target.style.top = startY + distance * Math.sin(direction) + 'px';
    }
  }
  animate();
}
</script>

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:js实现盒子拖拽动画效果 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • JS判断输入的字符串是否是数字的方法(正则表达式)

    判断一个字符串是否为数字,可以使用JavaScript中的正则表达式来实现。以下是判断一个字符串是否为数字的方法和过程: 1. 使用正则表达式匹配数字模式 使用正则表达式来匹配数字的模式是判断一个字符串是否为数字的核心。以下是一个匹配数字模式的正则表达式:/^[0-9]+$/。该正则表达式表示匹配从字符串的开头到结尾,包含0-9数字的字符串。 2. 建立判断…

    JavaScript 2023年5月28日
    00
  • JavaScript 数组遍历的五种方法

    JavaScript 数组遍历的五种方法如下: 1. forEach() array.forEach(function(currentValue, index, arr), thisValue) forEach() 方法用于调用数组中的每个元素,并将元素传递给回调函数。该方法不会返回新的数组,而是在原始数组中执行回调函数。回调函数可以接收三个参数:当前元素的…

    JavaScript 2023年5月27日
    00
  • 详谈javascript中DOM的基本属性

    当谈到JavaScript中的DOM(文档对象模型)时,我们需要了解DOM的基本属性。DOM是指在HTML文档中的每个元素都可以视为一个对象,而JavaScript可以用来访问和修改它们。 HTML元素的基本属性 HTML元素的基本属性通常可以通过查询DOM文档来找到。下面是访问HTML元素的基本属性的一些示例。 Element.innerHTML Elem…

    JavaScript 2023年6月10日
    00
  • Bootstrap弹出带合法性检查的登录框实例代码【推荐】

    针对这个问题,我来为你详细讲解一下”Bootstrap弹出带合法性检查的登录框实例代码”的攻略。 首先,我们需要明确几点: Bootstrap是一个开源的前端框架,提供了丰富的UI组件和布局; 该登录框实例需要使用Bootstrap和jQuery两个库,因此需要在页面中引入这两个库; 合法性检查是指在用户输入账号和密码后,是否满足一定的输入规则,比如不能为空…

    JavaScript 2023年6月10日
    00
  • Vue Element前端应用开发之开发环境的准备工作

    下面是“Vue Element前端应用开发之开发环境的准备工作”的完整攻略。 准备工作 在开始Vue Element前端应用开发之前,我们需要做一些准备工作。这些准备工作包括: 安装Node.js和npm 安装Vue CLI 创建项目 下面我们来详细介绍这些准备工作。 安装Node.js和npm Node.js是一个JavaScript的运行环境,它能帮我们…

    JavaScript 2023年6月10日
    00
  • JavaScript数组常用方法实例讲解总结

    JavaScript数组常用方法实例讲解总结 本文将对 JavaScript 数组常用方法进行实例讲解总结,旨在帮助读者更加深入地了解 JavaScript 数组的使用。本文涉及的方法包括:push、pop、shift、unshift、slice、splice、concat、join、indexOf 和 sort。 push方法 push方法可以向数组的末尾…

    JavaScript 2023年5月27日
    00
  • JavaScript实现简单进度条效果

    JavaScript实现简单进度条效果,可以通过改变进度条的宽度或者高度来实现。下面是实现的步骤: 步骤1. 创建HTML布局 进度条需要创建一个父容器,然后再创建一个子容器来表示进度。代码如下: <div class="progress-bar"> <div class="progress">…

    JavaScript 2023年6月11日
    00
  • JavaScript中Number对象的toFixed() 方法详解

    JavaScript中Number对象的toFixed() 方法详解 toFixed() 方法是JavaScript中Number对象的一个方法,可以将数字保留指定位数的小数。在本文中,我们将详细介绍这个方法的用法和示例,以便帮助读者更好地理解。 语法 toFixed() 方法的语法如下: number.toFixed([digits]) 其中,digits…

    JavaScript 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部