开始
最近有个需求,是这样的。项目键盘事件可以自定义键值。根据后台设置的键值,动态监听键盘键值。
首先看下接口返参结果:
{
"code": 0,
"data": [
{
"buttonKey": "W",
"buttonKeyName": "W",
"functionKey": "87",
"isCombination": 0
},
{
"buttonKey": "F",
"buttonKeyName": "F",
"functionKey": "70",
"isCombination": 1
}
]
}
问题
没有动态获取key值之前,我们可以这样监听:
-
全局监听
window.addEventListener('keydown', (event) => { console.log('event: ', event.key); });
这样每个页面都要做处理,如果还有组合键什么的就有点麻烦了。
-
使用
VueUse
的onKeyStroke
import { onKeyStroke } from '@vueuse/core'; onKeyStroke(['s', 'S', 'ArrowDown'], (e) => { e.preventDefault() })
-
首先是个动态获取值,如果一进来就监听, 就会出现拿不到键值对的情况。
-
如果监听当前页面,进入其他的页面有个相同的键值就会出现冲突。
-
思路
- 怎么使用自定义指令监听键盘事件?
- 怎么获取动态值?
- 怎么在不同页面解决冲突?
实现
如果没有用过自定义指令,可以看下用vue3自定义指令写一个按钮点击小优化 , 这个比较基础
-
添加自定义指令
keyboard
export const VKeyboard = { mounted: (el, binding) => { el.handler = function (event) { console.log(event) }; // 添加监听事件 document.addEventListener('keydown', el.handler); }, updated(el) { document.addEventListener('keydown', el.handler); }, // 绑定元素的父组件卸载后调用 unmounted: (el) => { // 删除监听事件 document.removeEventListener('keydown', el.handler); }, }
组件使用
<template> <div v-keyboard>延迟1s</div> </template>
-
怎么传值?获取最新值?
export const VKeyboard = { mounted: (el, binding) => { el.handler = function (event) { console.log(event) const { buttonKey, isCombination = 0 } = binding.value || el.valueKeys || {}; // 调用事件 buttonKey === currentKey && binding.arg && binding.arg(event) }; // 添加监听事件 document.addEventListener('keydown', el.handler); }, updated(el, binding) { // 更新获取最新键值 el.valueKeys = binding.value; document.addEventListener('keydown', el.handler); }, // 绑定元素的父组件卸载后调用 unmounted: (el) => { // 删除监听事件 document.removeEventListener('keydown', el.handler); }, }
组件使用
<template> <div v-keyboard:[keyHandle]="currentKey">延迟1s</div> </template> <script setup> const hotKeyList = ref([]); const getHotKeyList = async () => { const result = $api.getkeyList(); hotKeyList.value = result; }; const currentKey = computed(() => hotKeyList.value.find((item) => item.functionCode === 'cash_box')); const keyHandle = (event) => { console.log('event: ', event); }; </script>
-
解决不同页面的冲突
- 卸载组件删除监听事件
- 监听元素不存在时,删除监听事件,防止调用其事件
export const VKeyboard = { mounted: (el, binding) => { el.handler = function (event) { console.log(event) const { buttonKey, isCombination = 0 } = binding.value || el.valueKeys || {}; // 如果元素不存在,删除该元素监听事件,防止按键冲突 const isHasEl = document.contains(el); if (!isHasEl) { document.removeEventListener('keydown', el.handler); return; } // 调用事件 buttonKey === currentKey && binding.arg && binding.arg(event) }; // 添加监听事件 document.addEventListener('keydown', el.handler); }, updated(el, binding) { // 更新获取最新键值 el.valueKeys = binding.value; document.addEventListener('keydown', el.handler); }, // 绑定元素的父组件卸载后调用 unmounted: (el) => { // 删除监听事件 document.removeEventListener('keydown', el.handler); }, }
最后
这只是一个解决思路,具体逻辑要看具体需求。也希望大家能提出更好的办法,共同探讨学习。
详细的可查看文档:keyboard 监听键盘
使用:
// main.js
import { createApp } from 'vue';
import { directives } from '@kvuse/components';
import App from './App.vue';
const app = createApp(App);
// 自定义指令
app.directive('keyboard', directives.keyboard);