灵异事件——没点击按钮却触发了click事件

644 阅读1分钟

要点

button 点击之后处于聚焦状态,当键盘输入 EnterSpace 的时候会触发它的 click 事件

起因

当我以为这是最后一个Bug,改完就可以去吃饭时……没想到最后花了半天时间才找到根本原因……

当时正在写 Vue3 的项目,大致的流程是:

  1. 点击列表某一项的 button,弹出弹窗
  2. 用户扫码(本地用键盘模拟扫码,enter 键作为结束标志)
  3. 扫码成功之后做一些处理再关闭弹窗

QQ录屏20230511145012 -original-original.gif QQ录屏20230511140554 -original-original.gif

image.png image.png

然而经过排查会发现如上图所示,在第 2 步的时候又弹出了弹窗

当时我一脸问号,反复排查了流程中是否有多余的打开弹窗的语句,最后只锁定到了第 1 步的点击

至此我离真相只差一步,只要找到还有什么渠道会触发 click 事件,并且想办法屏蔽掉就 OK 了

d3391c6e8df7823d99c12b0f0efb693.jpg

そうですね ,按钮点击之后聚焦情况下,键盘输入 Enter 或 Space 会触发 click 事件

解决办法

由MDN已知:点击 <button> 会让浏览器和操作系统(默认情况下)将焦点放在其上。 <input> 的 type="button" 和 type="submit" 也是一样的

在聚焦状态,通过键盘 enter 或者 space键可以触发按钮的点击事件,要阻止这种行为思路有两种:

  • 点击按钮后让按钮失焦
  • 屏蔽按钮上的键盘事件

点击按钮后让按钮失焦

<button onclick="clickBtn"></button>
function clickBtn (e) {
    e.target.blur()
}

屏蔽按钮上的键盘事件

  • 在 Vue 中屏蔽
<!-- 阻止按钮监听所有键盘事件 -->
<button @keydown.prevent></button>
<!-- 阻止按钮监听键盘 enter 和 space 键按下 -->
<button @keydown.enter.prevent @keydown.space.prevent></button>
  • 原始
<button onkeydown="dealKeydown"></button>
// 对于 enter 或 space 键阻止原生行为
function dealKeydown (e) {
    if (e.keycode === 13 || e.keyCode === 32) {
        e.preventDefault()
    }
}