栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何使用JavaScript检测是否同时按下了多个键?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何使用JavaScript检测是否同时按下了多个键?

**注意:现已弃用

如果您了解概念,则可以轻松进行多次击键检测

我这样做的方式是这样的:

var map = {}; // You could also use an arrayonkeydown = onkeyup = function(e){    e = e || event; // to deal with IE    map[e.keyCode] = e.type == 'keydown';    }

这段代码非常简单:由于计算机一次只传递一个按键,因此创建了一个数组来跟踪多个按键。然后可以使用该数组一次检查一个或多个键。

只是为了说明一下,假设您按下

A
B
,每个按钮都会触发一个
keydown
事件,该事件设置
map[e.keyCode]
为的值
e.type ==keydown
,其结果为true或false。现在
map[65]
map[66]
都设置为
true
。当您放开时
A
,该
keyup
事件将触发,并导致相同的逻辑来确定
map[65]
(A)的相反结果,该结果现在为false,但是由于
map[66]
(B)仍处于“按下”状态(它尚未触发键入事件),它仍然是正确的。

map
通过这两个事件的数组如下所示:

// keydown A // keydown B[    65:true,    66:true]// keyup A// keydown B[    65:false,    66:true]

您现在可以做两件事:

A) 可以创建Keylogger示例作为参考,以供日后需要快速找出一个或多个键代码时使用。假设您已经定义了一个html元素,并使用变量指向了它

element

element.innerHTML = '';var i, l = map.length;for(i = 0; i < l; i ++){    if(map[i]){        element.innerHTML += '<hr>' + i;    }}

注意:您可以通过其

id
属性轻松获取元素。

<div id="element"></div>

这将创建一个html元素,可以轻松地在javascript中使用

element

alert(element); // [Object HTMLDivElement]

您甚至不必使用

document.getElementById()
$()
抓住它。但是出于兼容性考虑,
$()
更广泛地建议使用jQuery 。

只要确保 script 标记在HTML正文之后即可。 优化提示 :大多数大牌网站把脚本标签
body标签进行优化。这是因为script标记会阻止其他元素加载,直到脚本的下载完成为止。将其放在内容之前可以预先加载内容。

B(您感兴趣的地方) 您可以一次检查一个或多个键,

例如:

if(map[17] && map[16] && map[65]){ // CTRL+SHIFT+A    alert('Control Shift A');}else if(map[17] && map[16] && map[66]){ // CTRL+SHIFT+B    alert('Control Shift B');}else if(map[17] && map[16] && map[67]){ // CTRL+SHIFT+C    alert('Control Shift C');}

编辑 :这不是最可读的代码段。可读性很重要,因此您可以尝试这样的操作以使其更容易操作:

function test_key(selkey){    var alias = {        "ctrl":  17,        "shift": 16,        "A":     65,            };    return key[selkey] || key[alias[selkey]];}function test_keys(){    var keylist = arguments;    for(var i = 0; i < keylist.length; i++)        if(!test_key(keylist[i])) return false;    return true;}

用法:

test_keys(13, 16, 65)test_keys('ctrl', 'shift', 'A')test_key(65)test_key('A')

这是否更好?

if(test_keys('ctrl', 'shift')){    if(test_key('A')){        alert('Control Shift A');    } else if(test_key('B')){        alert('Control Shift B');    } else if(test_key('C')){        alert('Control Shift C');    }}

(编辑结束)


本实施例中检查

Ctrl``Shift``A
Ctrl``Shift``B
Ctrl``Shift``C

就这么简单:)

笔记

跟踪键码

通常,对代码进行编码是一种很好的做法,尤其是诸如键码之类的东西(如

// CTRL+ENTER
),这样您就可以记住它们是什么。

您还应该将键控代码与文档(

CTRL+ENTER => map[17] && map[13]
,NOT
map[13] &&map[17]
)放在相同的顺序。这样,当您需要返回并编辑代码时,您永远不会感到困惑。

if-else链的陷阱

如果检查不同数量的组合(如

Ctrl``Shift``Alt``Enter
Ctrl``Enter
),则将较小的组合放在较大的组合 之后,否则,如果较小的组合足够相似,则它们将覆盖较大的组合。例:

// Correct:if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER    alert('Whoa, mr. power user');}else if(map[17] && map[13]){ // CTRL+ENTER    alert('You found me');}else if(map[13]){ // ENTER    alert('You pressed Enter. You win the prize!')}// Incorrect:if(map[17] && map[13]){ // CTRL+ENTER    alert('You found me');}else if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER    alert('Whoa, mr. power user');}else if(map[13]){ // ENTER    alert('You pressed Enter. You win the prize!');}// What will go wrong: When trying to do CTRL+SHIFT+ENTER, it will// detect CTRL+ENTER first, and override CTRL+SHIFT+ENTER.// Removing the else's is not a proper solution, either// as it will cause it to alert BOTH "Mr. Power user" AND "You Found Me"

陷阱:“即使我不按任何键,此键组合也会继续激活”

处理警报或从主窗口获取焦点的任何内容时,您可能希望

map=[]
在条件完成后包括重置阵列。这是因为某些事情(例如
alert()
)会将焦点从主窗口移开,并导致“ keyup”事件不触发。例如:

if(map[17] && map[13]){ // CTRL+ENTER    alert('Oh noes, a bug!');}// When you Press any key after executing this, it will alert again, even though you // are clearly NOT pressing CTRL+ENTER// The fix would look like this:if(map[17] && map[13]){ // CTRL+ENTER    alert('Take that, bug!');    map = {};}// The bug no longer happens since the array is cleared

陷阱:浏览器默认值

我发现这是一件令人烦恼的事情,其中​​包括解决方案:

问题:由于浏览器通常对组合键具有默认操作(例如,

Ctrl``D
激活书签窗口或
Ctrl``Shift``C
在maxthon上激活skynote),因此您可能还需要添加
returnfalse
after
map = []
,因此当“重复文件”出现时,您网站的用户不会感到沮丧功能,放在上
Ctrl``D
,将页面标记为书签。

if(map[17] && map[68]){ // CTRL+D    alert('The bookmark window didn't pop up!');    map = {};    return false;}

没有

return false
弹出“书签”窗口,使用户感到沮丧。

退货单(新)

好的,因此您不一定总是要在此时退出该功能。这就是

event.preventDefault()
功能所在的原因。它的作用是设置一个内部标志,告诉解释,以
使浏览器运行的默认操作。之后,继续执行功能(而
return
将立即退出功能)。

在决定是否使用

return false
或区分之前,请先了解这种区别。
e.preventDefault()

event.keyCode
不推荐使用

用户SeanVieira在

event.keyCode
已弃用的评论中指出。

在那里,他给出了一个极好的选择:

event.key
,它返回所按下键的字符串表示形式,例如
"a"
for
A
"Shift"
for
Shift

我继续做饭,准备了一种检查所说弦的工具。

element.onevent
element.addEventListener

addEventListener
可向其注册的处理程序可以堆叠,并按注册顺序进行调用,而
.onevent
直接设置则相当激进,并会覆盖您以前拥有的任何内容。

document.body.onkeydown = function(ev){    // do some stuff    ev.preventDefault(); // cancels default actions    return false; // cancels this function as well as default actions}document.body.addEventListener("keydown", function(ev){    // do some stuff    ev.preventDefault() // cancels default actions    return false; // cancels this function only});

.onevent
属性似乎覆盖了所有内容和行为,
ev.preventDefault()
并且
return false;
可能是不可预测的。

在这两种情况下,通过注册的处理程序

addEventlistener
似乎都更易于编写和推理。

还有

attachEvent("onevent",callback)
InternetExplorer的非标准实现,但这已被弃用,甚至不涉及Javascript(它涉及一种称为 _Jscript_的神秘语言)。您的最大利益就是尽可能避免使用多语种代码。

帮手班

为了解决混乱/投诉,我编写了一个进行此类抽象的“类”(pastebin链接):

function Input(el){    var parent = el,        map = {},        intervals = {};    function ev_kdown(ev)    {        map[ev.key] = true;        ev.preventDefault();        return;    }    function ev_kup(ev)    {        map[ev.key] = false;        ev.preventDefault();        return;    }    function key_down(key)    {        return map[key];    }    function keys_down_array(array)    {        for(var i = 0; i < array.length; i++) if(!key_down(array[i]))     return false;        return true;    }    function keys_down_arguments()    {        return keys_down_array(Array.from(arguments));    }    function clear()    {        map = {};    }    function watch_loop(keylist, callback)    {        return function(){ if(keys_down_array(keylist))     callback();        }    }    function watch(name, callback)    {        var keylist = Array.from(arguments).splice(2);        intervals[name] = setInterval(watch_loop(keylist, callback), 1000/24);    }    function unwatch(name)    {        clearInterval(intervals[name]);        delete intervals[name];    }    function detach()    {        parent.removeEventListener("keydown", ev_kdown);        parent.removeEventListener("keyup", ev_kup);    }    function attach()    {        parent.addEventListener("keydown", ev_kdown);        parent.addEventListener("keyup", ev_kup);    }    function Input()    {        attach();        return { key_down: key_down, keys_down: keys_down_arguments, watch: watch, unwatch: unwatch, clear: clear, detach: detach        };    }    return Input();}

此类不会做所有事情,并且不会处理所有可能的用例。我不是图书馆员。但是对于一般的交互使用来说应该没问题。

要使用此类,请创建一个实例并将其指向要与键盘输入关联的元素:

var input_txt = Input(document.getElementById("txt"));input_txt.watch("print_5", function(){    txt.value += "FIVE ";}, "Control", "5");

这样做是使用将一个新的输入侦听器附加到元素上

#txt
(假设它是一个textarea),并为key组合设置一个观察点
Ctrl+5
。当
Ctrl
5
都关闭时,将调用您传入的回调函数(在本例中为添加
"FIVE"
到textarea 的函数)。回调与名称相关联
print_5
,因此只需将其删除即可:

input_txt.unwatch("print_5");

input_txt
txt
元素分离:

input_txt.detach();

这样,垃圾回收可以拾起对象(

input_txt
),如果将其丢弃,则不会留下旧的僵尸事件侦听器。

为了更全面,这里是对类API的快速参考,以C / Java样式表示,因此您知道它们返回的内容以及期望的参数。

Boolean  key_down (String key);

true
如果
key
关闭则返回,否则返回false。

Boolean  keys_down (String key1, String key2, ...);

true
如果所有键
key1 .. keyN
都按下,则返回,否则返回false。

void     watch (String name, Function callback, String key1, String

key2, …);

创建一个“观察点”,以便按全部

keyN
将触发回调

void     unwatch (String name);

通过名称删除所述观察点

void     clear (void);

擦除“按键失效”缓存。相当于

map = {}
以上

void     detach (void);

从父元素分离出

ev_kdown
ev_kup
侦听器,从而可以安全地摆脱实例

我希望这个 详尽解释的答案 迷你博客对您有所帮助:)



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/390622.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号