在按键时,运行 一个定时器只有一次 JavaScript

On keydown, run a timer only once with JavaScript

我正在制作一个网页游戏,我想在用户开始游戏时调用一个计时器。基本上,我的做法是当按下其中一个 WASD 键时,启动计时器。问题是,如果您多次敲击按键,它每次都会启动计时器。我只想调用该函数一次。我正在考虑 clearInterval(),但那会停止计时器。不理想。

这是我的代码。 (下图Fiddlelink)

我认为应该发生的是当按下任何键时,它会首先检查 fired 是否等于 false。如果是,请将其设置为 true。然后,如果按下 W、A、S 或 D 键,则启动计时器。

然后当按键恢复时,再次将 fired 设置为 false。

var fired = false;
var timer = document.getElementById("timer");

var playerObj = {
    elapsedTime: 0,
    startTimer: function () {
        setInterval(function () {
            playerObj.elapsedTime += 1;
            timer.innerHTML = playerObj.elapsedTime;
        }, 1000);
    }
};

var fired = false;
document.onkeydown = function (e) {
    var w = e.keyCode == '87',
        a = e.keyCode == '65',
        s = e.keyCode == '83',
        d = e.keyCode == '68';
    if (!fired) {
        fired = true;
        if (w || a || s || d) {
           playerObj.startTimer();
        }
    }
};

document.onkeyup = function () {
     fired = false;
};

我参考了 this question's 答案并尝试使用标志,但它似乎没有用。

Fiddle

我认为您需要更改流程以执行以下操作:

onkeydown 检查 w/a/s/d 标志,然后设置标志并启动计时器

onkeyup 如果不是 w/a/s/d 键,则将标志设置为 false

本质上就是您要在此处执行的操作。我认为这会有所不同,所以当 enter/g/h/etc 被击中时停止。

关键思想是仅当 firedfalse 时才启动计时器。 如果您希望计时器在每场比赛中启动一次,请在第一个按键事件上将 fired 设置为 true 并启动计时器。在随后的按键事件中,检查 fired 的值并拒绝启动计时器。

var fired = false;
var timer = document.getElementById("timer");

var playerObj = {
    elapsedTime: -1,
    update: function () {
      playerObj.elapsedTime += 1;
      timer.innerHTML = playerObj.elapsedTime;
    },
    startTimer: function () {
        playerObj.update();
        setInterval(playerObj.update, 1000);
    }
};

document.onkeydown = function (e) {
    var w = e.keyCode == '87',
        a = e.keyCode == '65',
        s = e.keyCode == '83',
        d = e.keyCode == '68';
    if (!fired) {
        fired = true;
        if (w || a || s || d) {
           playerObj.startTimer();
        }
    }
};
#timer {
  font-family: sans-serif;
  font-size: 24px;
  color: #444;
  border: 1px solid #ddd;
  display: inline-block;
  padding: 5px 15px;
}
<div id="timer">-</div>

另一种方法是在第一个按键事件之后替换按键处理程序。

var fired = false;
var timer = document.getElementById("timer");

var playerObj = {
    elapsedTime: -1,
    update: function () {
      playerObj.elapsedTime += 1;
      timer.innerHTML = playerObj.elapsedTime;
    },
    startTimer: function () {
        playerObj.update();
        setInterval(playerObj.update, 1000);
    }
};

var keyToString = {
  87: '&uarr;',
  65: '&larr;',
  83: '&darr;',
  68: '&rarr;'
};

function keyHandler(event) {             // Handles all valid keys.
  var display = document.getElementById('display');
  display.innerHTML = keyToString[event.keyCode];
}

document.onkeydown = function (event) {  // Handles the first valid key.
  if (keyToString[event.keyCode] !== undefined) {
    playerObj.startTimer();              // Start the timer.
    document.onkeydown = keyHandler;     // Replace this key handler.
    keyHandler(event);                   // Call the general key handler.
  }
};
#timer, #display {
  font-family: sans-serif;
  font-size: 24px;
  color: #444;
  padding: 5px 15px;
}
#timer {
  display: inline-block;
  border: 1px solid #ddd;
}
<div id="timer">-</div>

<div id="display"></div>

问题有点不清楚,所以这可能没有抓住重点。每点击一次 WASD 就会启动一次计时器。

var timer = document.getElementById("timer");

var playerObj = {
    elapsedTime: 0,
    startTimer: function () {
        setInterval(function () {
            playerObj.elapsedTime += 1;
            timer.innerHTML = playerObj.elapsedTime;
        }, 1000);
    }
};

// keep track of keys indiividually
var keyPressed = {
    w: false,
    a: false,
    s: false,
    d: false
};

// make it easy to translate keyCodes to key names
var CODES = {
    87: 'w',
    65: 'a',
    83: 's',
    68: 'd'
};

document.onkeydown = function (e) {

    // look up the key
    var keyName = CODES[e.keyCode];

    // if it's one we're interested in and it hasn't been pressed yet
    if (keyName && !keyPressed[keyName]) {
        playerObj.startTimer();

        // mark it as having been pressed
        keyPressed[keyName] = true;
    }
};

为此你根本不需要标志,你所要做的就是在计时器启动后将事件侦听器设置为 null,然后此函数将永远不会再次 运行。它比此处的其他解决方案更好,因为您不希望此功能 运行ning 可能会阻止 UI.

中的其他事件
document.onkeydown = function (e) {
    var w = e.keyCode == '87',
        a = e.keyCode == '65',
        s = e.keyCode == '83',
        d = e.keyCode == '68';

    if (w || a || s || d) {
       playerObj.startTimer();
       document.onkeydown = null;
    }
};