实现盒子拖拽动画效果需要以下步骤:
首先需要为需要拖拽的目标元素添加事件监听器,通常是mousedown
事件或者touchstart
事件。
let target = document.getElementById('drag-target');
target.addEventListener('mousedown', dragStart);
target.addEventListener('touchstart', dragStart);
其中dragStart
函数是拖拽开始的处理函数,我们接下来会讲到。
当用户开始拖拽目标元素时,我们需要对鼠标或手指的移动进行监听,并实时更新目标元素的位置,以实现拖拽效果。我们需要给目标元素的父元素绑定事件监听器,监听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
数组中第一个触摸点的位置。
在上一步拖动中,我们已经可以实现目标元素的拖动。接下来我们需要添加缓动效果,使目标元素在松开鼠标或手指时能够平稳地移动到目标位置。我们可以使用requestAnimationFrame
函数来实现动画效果。
首先,我们需要在mousedown
或touchstart
事件中记录目标元素的初始位置和事件发生的时间。
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};
// 在这里保存初始位置和时间
}
然后,我们可以在mousemove
或touchmove
事件中更新目标元素的位置,并计算出目标位置和当前位置之间的距离和时间间隔,以便计算缓动效果。
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;
}
最后,在mouseup
或touchend
事件中,我们可以根据移动距离和时间间隔计算出缓动效果的参数(速度和加速度),然后使用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();
}
这样,我们就实现了盒子拖拽动画效果。下面给出两个示例,分别实现了鼠标和触摸设备的拖拽效果。
<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>
<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>
本文链接:http://task.lmcjl.com/news/9660.html