键盘响应可能会变得异常复杂。通常你不想关注每个被触发的 keydown 事件,因为这取决于用户的键盘和设置;例如,一个事件最初触发,然后在暂停后触发快速流。当用户同时按住两个键时,还有一个问题。
以下代码通过单独的更新函数将键盘响应与动画分开。按下新的箭头键后,方块最初移动 1 步(设置为 5px),然后在 100 毫秒后连续移动,直到释放键。
(小提琴)
var directions = [],
lastPressTime, stepped, ti, frameRate = 30,
squareSpeed = 5, stepTime = 100;
function update() {
var x, y, d = directions[directions.length - 1],
square = document.getElementById('square');
if (!d) {
return;
}
if (new Date().getTime() < lastPressTime + stepTime) {
if (stepped) { // already stepped and <100ms has passed
return; // so do nothing
}
else {
stepped = true;
}
}
x = square.offsetLeft;
y = square.offsetTop;
if (d == 'left') {
x -= squareSpeed;
}
else if (d == 'right') {
x += squareSpeed;
}
else if (d == 'up') {
y -= squareSpeed;
}
else if (d == 'down') {
y += squareSpeed;
}
square.style.left = x + 'px';
square.style.top = y + 'px';
}
function checkArrowKeys(e) {
var arrs = [],
key = window.event ? event.keyCode : e.keyCode;
arrs[37] = 'left';
arrs[38] = 'up';
arrs[39] = 'right';
arrs[40] = 'down';
if (arrs[key]) {
return arrs[key];
}
}
document.onkeydown = function(e) {
var d = checkArrowKeys(e);
if (d) {
// Key not already pressed; add it to array
// of directions and step forward
if (directions.indexOf(d) === -1) {
directions.push(d);
lastPressTime = new Date().getTime();
stepped = false;
}
if (!ti) {
ti = setInterval(update, 1000 / frameRate);
}
}
};
document.onkeyup = function(e) {
var d = checkArrowKeys(e),
i;
if (d) {
i = directions.indexOf(d);
// remove this direction from the array of directions
if (i > -1) {
directions =
directions.slice(0, i).concat(directions.slice(i + 1));
}
// if no keys are down then stop updating
if (directions.length === 0) {
clearInterval(ti);
ti = null;
}
}
};