Appearance
Key Directive
源码
ts
/**
* @param {string} arg 键码
* @param {Function} funVal 执行的函数
*/
interface obj {
arg: string
funVal: Function
id: string | number
}
interface keys {
[s: string]: obj
}
const keys: keys = {}
/**
* 判断类型
* @param {Element} el
*/
type InputElement = HTMLInputElement | HTMLTextAreaElement
const ifType = (el: Element | null): InputElement | undefined => {
if (!el) return undefined
if (el.tagName == 'INPUT' || el.tagName == 'TEXTAREA')
return el as InputElement
const isElComponent =
el.classList.contains('el-input') || el.classList.contains('el-textarea')
const inner = isElComponent
? ((el.getElementsByClassName('el-input__inner')[0] ||
el.getElementsByClassName('el-textarea__inner')[0]) as
| InputElement
| undefined)
: undefined
return inner
}
app
.mount('#app')
.directive('press-key', {
mounted(el, bind) {
// 判断是否是 input 或者 textarea 需要注意的是 el-input是一个div元素
const inputNode = ifType(el)
if (!bind.arg) {
console.error('请绑定需要触发的键,例如v-press-key:s')
return
}
// 获取id
const id = Object.keys(bind.modifiers).length
? Object.keys(bind.modifiers)[0]
: ''
// 获取对象键值
const k =
inputNode == undefined
? bind.arg + (id ? '-' + id : '')
: bind.arg + '-' + inputNode.tagName + (id ? '-' + id : '')
console.log(keys, k)
if (Object.keys(keys).filter((item) => item == k).length) {
console.error('绑定的按键 ' + bind.arg + ' 与已有的重名')
return
}
// 储存数据
keys[k] = {
arg: bind.arg,
funVal: bind.value,
id,
}
// 绑定在input上时
if (inputNode !== undefined) {
inputNode.onkeydown = function keydown(event: KeyboardEvent) {
// 获取匹配项
const match = Object.keys(keys).filter((item) => {
const key = item.split('-')[0]
return (
event.key.toUpperCase() == key ||
event.key.toLowerCase() == key ||
event.key == key
)
})
console.log(match)
match.length &&
keys[
match[0].split('-')[0] +
'-' +
inputNode.tagName +
(id ? '-' + id : '')
].funVal()
}
return
}
window.onkeydown = function keydown(event: KeyboardEvent) {
if (ifType(document.activeElement)) {
return
}
// 获取匹配项
const match = Object.keys(keys).filter(
(item) =>
event.key.toUpperCase() == item ||
event.key.toLowerCase() == item ||
event.key == item
);
match.length && keys[match[0]].funVal();
}
},
})
注意
当指令绑定在 input
或者 textarea
或者 el-input
上时将为局部触发,否则将为全局触发.
函数如果需要携带参数,请使用箭头函数包裹。例如: v-press-key:q="() => msg('q')}"
如果不包裹的话,该函数会立即执行一次. id
为局部触发特有,全局使用将会无效。全局触发有多个按键相同时 将会优先触发第一个绑定的函数,并且会在控制台提示