键盘事件监听不生效的坑,我也踩了
大家好,我是星辰编程理财。最近,我在做一个项目时,遇到了一个问题。事情很简单:如下图,我需要给一个div
容器监听keydown
事件,然后在页面监听快捷键打开顶部的搜索面板。听起来挺简单对吧?我当时也这么想。
可是,不管我怎么写代码,keydown
事件就是死活不触发!无论是keydown
、keyup
还是keypress
,统统都不工作,我的代码就像没写一样,一片沉寂。这种感觉就像你给朋友发了条消息,却发现他一直在线就是不回你——太扎心了! 😅
解决思路
这种问题首先我还是直接扔给AI解答,但确实出来了一堆废话,效率不高。后来搜索了一遍,大概知道了是没聚焦
的问题,于是打算去mdn
看下keydown
详细文档。最后看详细文档找到了关键的一句话“键盘事件只能由 <inputs>, <textarea> 以及任何具有 contentEditable 或 tabindex="-1"属性的组件触发。”
,答案其实在一个属性上——tabindex
,给div
加个tabindex
属性就能搞定这个问题!却让我花了不少时间。 🪄✨
<div
class="window"
style={window.styleRecord[window.id]}
data-window-id={window.id}
on:keydown={onKeydown}
tabindex="-1"
>
{#if $showCmdInfo}
<CmdInfo windowId={window.id} />
{/if}
<Cmd windowId={window.id} />
<ModalAddCmdAlias windowId={window.id} />
{#if $search.isOpen}
<CmdSearchMain windowId={window.id} on:selectedSearchResult={search.close} />
{/if}
</div>
是不是很简单?只要在div
上加上tabindex="-1"
,就可以愉快地监听键盘事件了!
为什么需要tabindex
?
重点来了! 我之前一直忽略的一个事实是:默认情况下,只有某些特定的元素(如input
、textarea
、button
等)才能被“聚焦”(也就是接受用户输入焦点)。而像div
这种元素,虽然我们可以往上面写东西,甚至可以监听点击、鼠标悬浮等事件,但它不能接受键盘事件,因为它不能聚焦。
tabindex
就是为了解决这个问题的。它可以让任何元素变得可以被聚焦,从而接受键盘事件。
tabindex
的使用小窍门
你可能会想:“嘿,这个tabindex
到底是啥?” 简单来说,tabindex
是HTML元素的一个属性,它用来控制元素是否能通过键盘获取焦点,以及元素之间切换焦点的顺序。
tabindex
的取值解释:
-
tabindex="0"
:元素可以通过键盘导航获取焦点,并且焦点顺序会按照文档的结构顺序进行。如果你给一个div
加上tabindex="0"
,它就能像input
一样接受键盘事件。 -
tabindex="-1"
:元素不能通过键盘导航获得焦点,但仍然可以通过JavaScript调用focus()
方法来聚焦它。这种用法通常在一些复杂的自定义组件里很有用,比如我们想要通过编程来控制元素的焦点。 -
tabindex
大于0
:元素可以通过键盘导航获得焦点,并且优先级比tabindex="0"
更高,数值越小优先级越高。如果你给多个元素设置了不同的tabindex
值,按下Tab
键时它们会按照这个数值的顺序依次获得焦点。
问题解析:原理是什么?
回想一下刚开始为什么keydown
事件监听不到——其实问题的根源就在于焦点。浏览器里,键盘事件默认只触发在能够聚焦的元素上,而div
这样的元素默认是不能聚焦的。tabindex
就是用来改变这一行为的,它让非表单元素也能接受键盘输入。
所以,我们给div
加上了tabindex
,然后通过dom.focus()
让它真正获得焦点,这样键盘事件就可以正常触发了。
代码示例
来个完整的例子吧!当用户点击div
时,聚焦到这个元素,然后监听键盘输入,并且将用户按下的键展示在页面上。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Keyboard Event Example</title>
<style>
#editor {
width: 300px;
height: 100px;
border: 2px solid #333;
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="editor" tabindex="0">
键盘事件
</div>
<script>
const dom = document.getElementById('editor');
// 点击时聚焦到div元素
dom.addEventListener('click', () => dom.focus());
// 监听keydown事件
dom.addEventListener('keydown', (e) => {
dom.textContent = `keydown: ${e.key}`;
});
</script>
</body>
</html>
这个例子很简单:当你点击这个div
后,它会获得焦点,之后按下任何键盘键,页面上会显示你按下了什么键。🎉
小结
这是一个非常基础的问题,但在前端开发中大概率容易疏忽掉。前端知识点很多,不能一一记住,还得具体问题具体分析,才能游刃有余地应对各种需求。 👨💻👩💻