我想知道当用户停止拖动元素时如何获取距离和时间的值。 经过一番研究,我听说了加速度和速度的概念,但我仍然很困惑。
说明此动画的一些示例:
- https://codepen.io/osublake/details/jbRaMY
- https://codepen.io/osublake/pen/YrXdGZ
- https://codepen.io/mallendeo/pen/wBJQvp
这是我陷入困境的情况:
let draggableEl = document.getElementById('draggable');
let mousePos = { x: -1, y: -1 };
draggableEl.addEventListener('mousedown', onMousedown);
function onMousedown(e) {
document.documentElement.addEventListener('mouseup', onMouseup);
document.documentElement.addEventListener('mousemove', updateMousePos);
updateMousePos(e);
updateUI();
}
function onMouseup() {
document.documentElement.removeEventListener('mousemove', updateMousePos);
mousePos.x = -1;
mousePos.y = -1;
// Now how to get the time and throwVal ?
// draggableEl.style.transition = `transform ${time} ease-out-in`
// draggableEl.style.transform = `translate(${throwVal.x}, ${throwVal.y})`
}
function updateMousePos(e) {
mousePos.x = e.pageX;
mousePos.y = e.pageY;
}
function updateUI() {
if (mousePos.x === -1 && mousePos.y === -1)
return;
draggableEl.style.transform = `translate( ${mousePos.x}px, ${mousePos.y}px)`;
requestAnimationFrame(updateUI);
}
#draggable {
position: absolute;
background: red;
width: 100px;
height: 100px;
cursor: grab;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Drag</title>
</head>
<body>
<div id="draggable">Drag me</div>
</body>
</html>
最佳答案
我们可以设置让可拖动元素在一定时间后停止,而不是计算可拖动元素停止所需的时间(这涉及到一些相对复杂的物理公式)。
为了使其更加真实,我们可以使用cubic-bezier
函数。使用它,我们可以模拟它,使它看起来像是在失去速度。我们不必完全模仿物理学的工作方式(使用幻觉)。
这是一个工作示例(带有一些关于其工作原理的评论)。我还修改了一些代码,以便初始 mousedown
事件不会移动元素。
let draggableEl = document.getElementById('draggable');
let mousePos = {
x: -1,
y: -1,
started: false,
startX: -1,
startY: -1
};
// Used to track the last UI's transform position after the deceleration
// and also after any dragging
let uiTransform = {
x: 0,
y: 0
};
// Used to simulate UI's deceleration
let uiMotion = {
oldX: -1,
oldY: -1,
x: -1,
y: -1
};
draggableEl.addEventListener('mousedown', onMousedown);
function onMousedown(e) {
// Extract the last transform value
// Necessary because deceleration may be stopped by mousedown
// before the UI's natural deceleration is finished
let transformsValue = draggableEl.style.transform.match(/(-?\d*\.?\d+)/g)
draggableEl.style.transition = 'none'
uiTransform.x = (transformsValue && parseFloat(transformsValue[0])) || 0
uiTransform.y = (transformsValue && parseFloat(transformsValue[1])) || 0
uiTransform.offsetTop // Trigger layout reflow so that transition none is applied
draggableEl.style.transform = `translate(${uiTransform.x}px, ${uiTransform.y}px)`
document.documentElement.addEventListener('mouseup', onMouseup);
document.documentElement.addEventListener('mousemove', updateMousePos);
updateMousePos(e);
updateUI();
}
function onMouseup() {
document.documentElement.removeEventListener('mouseup', onMouseup);
document.documentElement.removeEventListener('mousemove', updateMousePos);
uiTransform.x += mousePos.x - mousePos.startX
uiTransform.y += mousePos.y - mousePos.startY
// The throwVal you asked for
// Time to decelerate is 1s
let throwVal = {
x: (uiMotion.x - uiMotion.oldX) * 3,
y: (uiMotion.y - uiMotion.oldY) * 3
}
draggableEl.style.transition = `transform 1s cubic-bezier(.27,1.04,.61,.97)`
draggableEl.style.transform = `translate(${uiTransform.x + throwVal.x}px, ${uiTransform.y + throwVal.y}px)`
mousePos.x = -1;
mousePos.y = -1;
mousePos.startX = -1;
mousePos.startY = -1;
mousePos.started = false;
uiMotion.x = -1
uiMotion.y = -1
uiMotion.oldX = -1
uiMotion.oldY = -1
}
function updateMousePos(e) {
if (!mousePos.started) {
mousePos.startX = e.pageX;
mousePos.startY = e.pageY;
mousePos.started = true;
}
mousePos.x = e.pageX;
mousePos.y = e.pageY;
}
function updateUI() {
if (mousePos.x === -1 && mousePos.y === -1)
return;
// Fixed some code
let xValue = uiTransform.x + mousePos.x - mousePos.startX
let yValue = uiTransform.y + mousePos.y - mousePos.startY
draggableEl.style.transform = `translate(${xValue}px, ${yValue}px)`;
if (uiMotion.oldX === -1 && uiMotion.oldY === -1) {
uiMotion.oldX = xValue
uiMotion.oldY = yValue
} else {
if (uiMotion.x !== -1 && uiMotion.y !== -1) {
uiMotion.oldX = uiMotion.x
uiMotion.oldY = uiMotion.y
}
uiMotion.x = xValue
uiMotion.y = yValue
}
requestAnimationFrame(updateUI);
}
html {
background: #121212;}
#draggable {
position: absolute;
background: #585858;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: grab;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Drag</title>
</head>
<body>
<div id="draggable"></div>
</body>
</html>
关于javascript - 获取拖动元素抛出时的距离和时间值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61339462/