监听键盘事件
在 vue 中,我们可以通过v-on
指令来监听 DOM 事件。对于键盘事件,我们可以使用@keyup
或者@keydown
等事件。这种方式,虽然有点违背了关注点分离,但如它官方文档介绍,带来了如下一些好处。
- 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
- 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
我们可以看一下之前的键盘事件都是怎么处理的:
$(document).keydown(function (e) {
e = e || event;
e.stopPropagation();
// esc 键关闭所有打开的div
if (e.keyCode == 27) {
escClosePopup();
return;
}
if (e.keyCode == 13) {
const target = e.target ? e.target : e.srcElement;
if(target.name === 'test1') {
...
}
}
});
这种集中式地管理会导致整个document
都会受该代码的侵入式影响,看似节省了一些代码,却带来更大的问题。我们只针对特定的 DOM 去绑定@keydown
事件就无需担心这种副作用。
处理中文输入法的回车
我们通过@keydown.enter
修饰符就可以处理回车事件。但在实际工作中,我们的使用场景会变得复杂起来。比如第一个场景,处理中文输入法的回车:
在表单提交的时候,我们经常会用Enter
键来快速操作。但是我们使用中文输入法时,期望的是输入英文,而不是直接提交。虽然正确的使用方式是按Space
键,但是很多用户的行为已经很难纠正过来,我们不得不去处理这种情况。
解决方案
在vue2
中,我们可以使用@keydown.13
来解决这个问题。 因为对于中文输入法来说,Enter
对应的Keycode
值是229
。我们只针对默认输入法的13
来进行处理,就可以规避掉这个问题。
由于keyCode这个属性从 web 标准中删除了,vue3 不再支持@keydown.13
这种写法,但是KeyboardEvent
里仍然保留了keyCode
属性。所以在 vue3 中,我们需要手动处理一下。目前,我的做法是使用一个高阶函数来专门处理中文输入法。
<template>
<input v-model="input" placeholder="请输入内容" @keydown.enter="handleKeyBoard($event, handleEnter)"/>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import { handleKeyBoard } from '@/composition/_keyboard'
export default defineComponent({
setup() {
const handleEnter = (e: KeyboardEvent) => {
console.log('触发enter', e)
}
return {
input: ref(''),
handleEnter,
handleKeyBoard
}
}
})
</script>
/**
* 高阶函数,处理中文输入法
* @param e
* @param handle
* @returns
*/
export function handleKeyBoard(e: KeyboardEvent, handle: Function) {
if (e.keyCode === 229) {
return
}
handle(e)
}
这种方式需要注意一下浏览器的兼容性。关于浏览器的Keyboard
事件,因为不同的厂商等原因,一直都没有被规范化,也是前端的一大痛点。这里有几篇文章对它做了深入的研究:
处理Shift+Enter换行
在有些场景中,我们需要支持按 Enter 提交,Shift+Enter 换行。对于这种需求,我们可以利用.exact
修饰符
<input v-model="input" placeholder="请输入内容" @keydown.enter.exact="handleKeyBoard($event, handleEnter)" />
处理组件的键盘事件
如果我们在组件上使用@keydown
是没有效果的,比如Element UI 的<el-input>
。为了解决这个问题,在 vue2 中我们可以使用.native
修饰符,它可以监听组件根元素的原生事件。
<el-input v-model="input" @keydown.enter.native="handleEnter"></el-input>
在 vue3 中,.native
修饰符被移除了:移除 v-on.native 修饰符。同时,新增的 emits
选项允许子组件定义真正会被触发的事件。对于子组件中未被定义为组件触发的所有事件监听器,Vue 现在将把它们作为原生事件监听器添加到子组件的根元素中 (除非在子组件的选项中设置了 inheritAttrs: false
)。
所以我们会发现基于 vue3 重写的Element Plus不需要再指定.native
修饰符了。