如何判断一个元素是否接受键盘输入?

6

我正在为一个网页应用程序编写键盘快捷键,并需要检查按键是否触发快捷方式,还是用户正在输入而不应触发快捷方式。

例如,常见的模式是使用/s键打开全局搜索栏。显然,如果用户正在输入到另一个输入框,则不应该打开搜索栏。

理想的逻辑大致如下: 按键按下时,检查当前聚焦的元素。如果该元素接受键盘输入(即可键入),则不执行任何操作。如果该元素不能接受键盘输入,则运行快捷方式。

请注意,仅检查可聚焦性是不够的,因为链接和按钮是可聚焦的,但并不接受键盘输入(在此处我的意思是这种输入方式)。

以下是我目前拥有的内容:

function acceptsKeyboardInput(element) {
    return (
        element.tagName === "INPUT" ||
        element.tagName === "TEXTAREA" ||
        element.isContentEditable
    );
}

这种方法是否涵盖了所有情况,还是有更好的方法来判断一个HTML元素是否接受键盘输入?


这似乎是一个不错的非冗长检查,为什么你在寻找替代方案?它没有按照预期工作吗? - Cesare Polonara
基本上,任何可聚焦的元素都应该能够接收键盘输入。您可以在此处阅读有关此内容的官方文档:键盘 - 可访问性。您可以查看此问题,了解如何检测元素是否可聚焦。 - icecub
1
@CesarePolonara 我在写这个问题的时候编写了那段代码,所以我可能已经解决了它。但现在我只是想检查是否有内置的API可以完成这个任务(或更直接的方法),或者是否有我遗漏的情况。 - Henry Woody
我相信只有表单元素具有“readOnly”属性。我知道这并没有回答你的问题,但也许可以帮助一下。 - Spencer May
1
据我所知,没有标准的方法可以检测元素是否接受键盘输入,例如“可键入”。您可能需要列出可以键入的标准元素和/或属性列表,并最终检查全局属性.isContentEditable,以查看您已赋予contenteditable属性的任何其他元素。 - icecub
显示剩余5条评论
2个回答

2

根据我所见,问题中提供的建议似乎是最好的方法——需要进行一些调整。

第一个改进是黑名单一组不接受键盘输入的输入类型(例如复选框或单选按钮)。我发现使用黑名单比使用白名单更容易和更好,原因有两个。第一个是为了未来支持的新输入类型和你可能错过的情况做好准备。第二个更重要的原因是,无效的输入类型默认返回文本类型,这意味着有无限数量的输入类型可以接受键盘输入。

第二个变化是还包括 <select> 元素,因为它们可以作为搜索/快速选择功能进行输入。

以下是完整的函数:

const nonTypingInputTypes = new Set([
    "checkbox",
    "radio",
    "button",
    "reset",
    "submit",
    "file",
]);

export function acceptsKeyboardInput(element) {
    return (
        (element.tagName === "INPUT" && !nonTypingInputTypes.has(element.type)) ||
        element.tagName === "TEXTAREA" ||
        element.tagName === "SELECT" ||
        element.isContentEditable
    );
}

还有一些其他的输入类型不接受键盘输入,但在浏览器中支持程度较低(例如颜色),因此我尽量只列出了常用且广泛实现的输入类型。


请记住,所有这些输入类型都接受有限数量的按键输入,出于辅助功能的原因,这些按键可能不应该被拦截:
  • 复选框:空格
  • 单选按钮:Tab、Shift+Tab、空格、左箭头、右箭头、上箭头、下箭头
  • 按钮:Enter、空格
  • 重置:Enter、空格
  • 提交:Enter、空格
  • 文件:Enter、空格
- undefined

0

所有的快捷键都会超过一个按键吗?如果是这样,您可以监听 input 并使用布尔值阻止快捷键运行。

var is_input = false
window.addEventListener('keydown', function (e) {
    console.log(is_input)
    is_input = false
})
window.addEventListener('input', function (e) {
    is_input = e.constructor.name == 'InputEvent'
})

当能够输入时,/s 的预期输出应为 true 或 false(取决于先前的 is_input 值),在 / 键按下 时为 true,在 s 键按下 及其后的所有键上为 true

当无法输入时,/s 的预期输出应为 true 或 false(取决于先前的 is_input 值),在 / 键按下 时为 false,在 s 键按下 及其后的所有键上为 false


注意:这适用于所有输入,包括可编辑的HTML内容。但是,我注意到在标准的“select”元素中进行类型搜索时,并不会调用keydown。 - Spencer May
有趣的方法。我认为这个方法存在的问题在于复杂性,因为你不能依赖事件监听器调用的顺序(在不同的浏览器中实现方式不同),这将需要以一种单独的方式来运行实际逻辑(可能需要使用超时),并且这还会进一步引入并发问题。 - Henry Woody
@HenryWoody,有没有可能出现 input 不遵循 keydown 的情况?我相信键盘事件总是会在 DOM 更改之前触发。 - Spencer May
@HenryWoody 我决定尝试使用这种方法制作自己的库,而且我不得不选择超时方法以防设置单个字符快捷方式。我仍在研究DOM触发顺序,但找不到输入不会立即跟随keydown的用例。你应该去看看!github.com/kapenike/OmniKeys - Spencer May

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