键盘事件监听不生效的坑,我也踩了

大家好,我是星辰编程理财。最近,我在做一个项目时,遇到了一个问题。事情很简单:如下图,我需要给一个div容器监听keydown事件,然后在页面监听快捷键打开顶部的搜索面板。听起来挺简单对吧?我当时也这么想。

可是,不管我怎么写代码,keydown事件就是死活不触发 !无论是keydown、keyup还是keypress,统统都不工作,我的代码就像没写一样,一片沉寂。这种感觉就像你给朋友发了条消息,却发现他一直在线就是不回你------太扎心了! 😅

解决思路

这种问题首先我还是直接扔给AI解答,但确实出来了一堆废话,效率不高。后来搜索了一遍,大概知道了是没聚焦的问题,于是打算去mdn看下keydown详细文档。最后看详细文档找到了关键的一句话"键盘事件只能由 <inputs>, <textarea> 以及任何具有 contentEditable 或 tabindex="-1"属性的组件触发。",答案其实在一个属性上------tabindex,给div加个tabindex属性就能搞定这个问题!却让我花了不少时间。 🪄✨

html 复制代码
<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的取值解释:

  1. tabindex="0" :元素可以通过键盘导航获取焦点,并且焦点顺序会按照文档的结构顺序进行。如果你给一个div加上tabindex="0",它就能像input一样接受键盘事件。

  2. tabindex="-1" :元素不能通过键盘导航获得焦点,但仍然可以通过JavaScript调用focus()方法来聚焦它。这种用法通常在一些复杂的自定义组件里很有用,比如我们想要通过编程来控制元素的焦点。

  3. tabindex大于0 :元素可以通过键盘导航获得焦点,并且优先级比tabindex="0"更高,数值越小优先级越高。如果你给多个元素设置了不同的tabindex值,按下Tab键时它们会按照这个数值的顺序依次获得焦点。

问题解析:原理是什么?

回想一下刚开始为什么keydown事件监听不到------其实问题的根源就在于焦点 。浏览器里,键盘事件默认只触发在能够聚焦的元素上,而div这样的元素默认是不能聚焦的。tabindex就是用来改变这一行为的,它让非表单元素也能接受键盘输入。

所以,我们给div加上了tabindex,然后通过dom.focus()让它真正获得焦点,这样键盘事件就可以正常触发了。

代码示例

来个完整的例子吧!当用户点击div时,聚焦到这个元素,然后监听键盘输入,并且将用户按下的键展示在页面上。

html 复制代码
<!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后,它会获得焦点,之后按下任何键盘键,页面上会显示你按下了什么键。🎉

小结

这是一个非常基础的问题,但在前端开发中大概率容易疏忽掉。前端知识点很多,不能一一记住,还得具体问题具体分析,才能游刃有余地应对各种需求。 👨‍💻👩‍💻

相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万5 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大6 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师6 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学6 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端