由于js是单线程,以及浏览器的键盘事件,最多只能做到关于Ctrl、Shift、Alt加任意一个的键位,无法做到同时使用方向键上和右,这在网页游戏中是致命的,所以在下实现了多重组合键的事件绑定
注意在使用组合键事件时,暂不支持声明Ctrl++这种按键,最好避免使用 ‘+’ 和 ‘‘ 的键位,因为 ‘+’ 作为连接组合键,’‘作为键盘事件的命名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| class KeyboardBinding { index: number events: Record<string, (e: KeyboardEvent) => void> keydownArr: string[]
constructor() { this.index = 0 this.events = {} this.keydownArr = [] window.addEventListener('keydown', this._event.bind(this)) window.addEventListener('keypress', this._event.bind(this)) window.addEventListener('keyup', this._event.bind(this)) window.addEventListener('blur', () => { this.keydownArr = [] }) }
_event(e: KeyboardEvent) { if (e.type === 'keydown') { if (this.keydownArr.findIndex((k: string) => k === e.key) < 0) { this.keydownArr.push(e.key) } } else if (e.type === 'keyup') { this.keydownArr = this.keydownArr.filter((k: string) => k !== e.key) }
if (this.keydownArr.length <= 0) return
const keys = Object.keys(this.events) if (keys.length <= 0) return
for (const key of keys) { const multiKeyArr = key.substring(0, key.lastIndexOf('_')).split('+') if (multiKeyArr.length === this.keydownArr.length) { if ( multiKeyArr.filter((k) => this.keydownArr.includes(k)).length === this.keydownArr.length ) { this.events[key](e) break } } } }
subscribe(keyboard: string, eventFn: (e: KeyboardEvent) => void): string { const key = `${keyboard}_${this.index++}` this.events[key] = eventFn return key }
unsubscribe(key: string) { if (Object.keys(this.events).filter((k) => k === key)[0]) { delete this.events[key] } } }
const keyboards: KeyboardBinding = bootstrap()
function bootstrap() { return new KeyboardBinding() }
export default keyboards
|
源码学习
Keyboard Bindings - CodePenhttps://codepen.io/EvilChan/pen/rNqJjvZ