Javascript onkeydown事件只触发一次?

29

我希望当用户按下某个键时,onkeydown事件只触发一次函数。如果要再次触发该函数,则必须释放该键并再次按下或长按。 我知道这很简单,但我还是很新手。另外,我希望避免使用jQuery或其他库。 还有一件事,这应该在IE和Firefox中都能正常工作。

8个回答

40

@SebastianBudka 为什么这样做?我个人认为,如果可感知的话,从性能上讲这会更快,更不用说可读性了。 - Adam
@Adam 我在前端世界还比较新手... 老实说,我当时脑子里根本没有想法。可能我认为 document.addEventListener('keydown', ...)element.onkeydown 更糟糕吧。为了后代,我删除了之前的评论。 - Sebastian Budka

30
您可以设置一个标志:
var fired = false;

element.onkeydown = function() {
    if(!fired) {
        fired = true;
        // do something
    }
};

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

或者解绑并重新绑定事件处理程序(可能更好):

function keyHandler() {
     this.onkeydown = null;
     // do something
}

element.onkeydown = keyHandler;

element.onkeyup = function() {
    this.onkeydown = keyHandler;
};

了解“传统”事件处理的更多信息。

您可能还想使用addEventListenerattachEvent来绑定事件处理程序。如需更多信息,请查看quirksmode.org - 高级事件注册模型


6

2

这里是一种使用addEventListenerremoveEventListener的方法。

var textBox = document.getElementById("textBox");
function oneKeyDown(){
    $("body").append("<h1>KeyDown<h1>"); //just to show the keypress
    textBox.removeEventListener('keydown', oneKeyDown, false);
}
function bindKeyDown(){
  textBox.addEventListener('keydown', oneKeyDown, false);
}
textBox.addEventListener('keyup', bindKeyDown, false)   
bindKeyDown();

jsfiddle上有代码示例。

需要注意的是,对于IE浏览器,您需要使用attachEventdetachEvent方法。


请注意,这仅适用于Webkit和Firefox。IE使用attachEvent - Felix Kling
忘了提到这件事,谢谢你的提醒。 - Mark Coleman

1

给你:

test.onkeydown = function() {
    if ( this.className === 'hold' ) { return false; }
    this.className = 'hold';

    // call your function here
};

test.onkeyup = function() {
    this.className = '';
};

现场演示:http://jsfiddle.net/simevidas/xAReL/2/


0

JQuery的one会对你有所帮助。

它的作用是将事件处理程序绑定到事件上,当事件发生时,运行事件处理程序并解除绑定,以便在下一个事件中不再触发。


2
我更喜欢避免使用jQuery或其他库。而且one本身并没有帮助。你必须重新绑定事件处理程序。 - Felix Kling

0

这是我的解决方案,它只会在目标(例如window或某个input字段)上首次按下键时运行您传递的函数。如果用户想再次触发键,则必须释放它并再次按下。


原生 JS

const onKeyPress = (func, target = window) => {
  // persistent "store" to track what keys are being pressed
  let pressed = {};

  // whenever a keydown event is fired ontarget element
  const onKeyDown = (event) => {
    // if key isn't already pressed, run func
    if (!pressed[event.which])
      func(event);

    // add key to store
    pressed = { ...pressed, [event.which]: true };
  };

  // whenever a keyup event is fired on the window element
  const onKeyUp = (event) => {
    const { [event.which]: id, ...rest } = pressed;
    // remove key from store
    pressed = rest;
  };

  // add listeners
  target.addEventListener('keydown', onKeyDown);
  window.addEventListener('keyup', onKeyUp);

  // return a function that can be called to remove listeners
  return () => {
    target.removeEventListener('keydown', onKeyDown);
    window.removeEventListener('keyup', onKeyUp);
  };
};

然后使用它:

const removeListener = onKeyPress((event) => console.log(event.which + ' key pressed'))

removeListener(); // when you want to remove listeners later

React和React Hooks

import { useState } from 'react';
import { useEffect } from 'react';
import { useCallback } from 'react';

export const useKeyPress = (func, target = window) => {
  // persistent "store" to track what keys are being pressed
  const [pressed, setPressed] = useState({});

  // whenever a keydown event is fired ontarget element
  const onKeyDown = useCallback(
    (event) => {
      // if key isn't already pressed, run func
      if (!pressed[event.which])
        func(event);

      // add key to store
      setPressed({ ...pressed, [event.which]: true });
    },
    [func, pressed]
  );

  // whenever a keyup event is fired on the window element
  const onKeyUp = useCallback((event) => {
    // remove key from store
    const { [event.which]: id, ...rest } = pressed;
    setPressed(rest);
  }, [pressed]);

  useEffect(() => {
    // add listeners when component mounts/changes
    target.addEventListener('keydown', onKeyDown);
    window.addEventListener('keyup', onKeyUp);

    // cleanup/remove listeners when component unmounts/changes
    return () => {
      target.removeEventListener('keydown', onKeyDown);
      window.removeEventListener('keyup', onKeyUp);
    };
  }, [target, onKeyDown, onKeyUp]);
};

然后使用它:

import { useKeyPress } from 'wherever';

useKeyPress((event) => console.log(event.which + ' key pressed'))

0

正如其他答案所述,没有“onkeyfirstdown”或类似的事件可供监听。

最好的解决方案是在js对象中跟踪已经按下的键:

var keysdown = {};

element.addEventListener('keydown', function(evt) {
  if(!(evt.key in keysdown)) {
    keysdown[evt.key] = true;
    // key first pressed
  }
});

element.addEventListener('keyup', function(evt) {
  delete keysdown[evt.key];
});

这样,如果按下多个键,则不会跳过“keyfirstpressed”事件。

(这里发布的许多其他解决方案仅在没有其他键按下时触发)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接