我正在尝试使箭头按下时使框沿水平和垂直方向移动。但是,当我以up arrow
和right arrow
为例时,它是对角线的。这是我的codepen
.box {
background-color: gray;
height: 100px;
width: 100px;
transition: margin 0.5s cubic-bezier(0, .7, 0, 1);
}
const box = document.getElementsByClassName('box')[0];
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px';
console.log(box.style.marginLeft, box.style.marginTop)
switch(keycode) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
});
您都可以在此处实现Promise
解决方案,但我认为这没有必要。基本上,我们可以做的是将所有按下的键存储在一个数组中,并确保javascript每x
毫秒仅通过一次按下的键数组once。
const box = document.getElementsByClassName('box')[0];
let pressedKeys = [];
let timeoutHandler = -1;
document.addEventListener('keydown', function({keyCode, which}) {
// As soon as the user presses a key we will clear the time out
clearTimeout(timeoutHandler);
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px';
pressedKeys.push(keycode);
// register the timeout to a variable in order for this function
// only run once every x second. This implementation is also
// known as 'debounce function to poor people'
timeoutHandler = setTimeout(() => {
pressedKeys.forEach((key, index) => {
// The animation time for each key pressed will be incremental
// which means the second key pressed will have an animation delay
// higher than the first one
const timeoutSeconds = index === 0 ? 1 : index + (index * 100);
setTimeout(() => {
switch(key) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
}, timeoutSeconds)
});
pressedKeys = [];
}, 100)
});
尝试以下操作:
const box = document.getElementsByClassName('box')[0];
let moving = false;
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px';
console.log(box.style.marginLeft, box.style.marginTop)
if (!moving && [37, 38, 39, 40].includes(keycode)){
switch(keycode) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
moving = true;
window.setTimeout(() => moving = false, 400); // Not 500, because visually it is very slow towards the end anyway.
}
});
一种可能的解决方案:您可以跟踪请求了哪些移动,并等待执行移动,直到上一个移动完成为止。示例:
const box = document.getElementsByClassName('box')[0];
const startValue = '0px';
const shiftValue = '400px';
function moveDown() {
// The move* functions only perform the move if is valid - i.e.,
// if it would actually cause a visible change.
if (box.style.marginTop !== shiftValue) {
box.style.marginTop = shiftValue;
return true;
}
// The move* functions return true iff the move was made.
return false;
}
function moveRight() {
if (box.style.marginLeft !== shiftValue) {
box.style.marginLeft = shiftValue;
return true;
}
return false;
}
function moveUp() {
if (box.style.marginTop !== startValue) {
box.style.marginTop = startValue;
return true;
}
return false;
}
function moveLeft() {
if (box.style.marginLeft !== startValue) {
box.style.marginLeft = startValue;
return true;
}
return false;
}
const moves = [];
let timeOfLastMoveInMilliseconds = null;
const animationDurationInSeconds = 0.5; // should match css transition duration
const animationDurationInMilliseconds = animationDurationInSeconds * 1000;
function onFrame() {
if (!timeOfLastMoveInMilliseconds) {
timeOfLastMoveInMilliseconds = performance.now();
}
const timeSinceLastMove = performance.now() - timeOfLastMoveInMilliseconds;
if (moves.length > 0 && timeSinceLastMove >= animationDurationInMilliseconds) {
const wasMoved = moves.pop()();
if (wasMoved) {
timeOfLastMoveInMilliseconds = performance.now();
}
}
window.requestAnimationFrame(onFrame);
}
window.requestAnimationFrame(onFrame);
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which;
switch(keycode) {
case(40):
moves.unshift(moveDown);
break;
case(39):
moves.unshift(moveRight);
break;
case(38):
moves.unshift(moveUp);
break;
case(37):
moves.unshift(moveLeft);
break;
}
});
请注意,上面的代码会跟踪用户的每一个举动,因此,例如,如果您快速向下,向上,向下,向上,向下按下,则该序列将回放。根据您的应用程序,您可能需要添加限制,例如,仅允许水平和对角线移动和/或仅在短时间内发生的来自按键的移动。