mirror of
https://github.com/zhigang1992/react.git
synced 2026-03-26 06:55:07 +08:00
feat: useKeyboard hooks (#541)
* feat(keyboard): create keyboard hooks * feat(usekeyboard): redesign event handler to match keyboard events from browser \ * test(usekeyboard): add testcase * docs(usekeyboard): create new hooks document
This commit is contained in:
@@ -14,6 +14,7 @@ export { default as useClickAway } from './use-click-away'
|
||||
export { default as useClipboard } from './use-clipboard'
|
||||
export { default as useCurrentState } from './use-current-state'
|
||||
export { default as useMediaQuery } from './use-media-query'
|
||||
export { default as useKeyboard, KeyMod, KeyCode } from './use-keyboard'
|
||||
export { default as Avatar } from './avatar'
|
||||
export { default as Text } from './text'
|
||||
export { default as Note } from './note'
|
||||
|
||||
177
components/use-keyboard/__tests__/keyboard.test.tsx
Normal file
177
components/use-keyboard/__tests__/keyboard.test.tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'enzyme'
|
||||
import { useKeyboard, KeyMod, KeyCode } from 'components'
|
||||
import { renderHook, act } from '@testing-library/react-hooks'
|
||||
import { KeyboardResult } from '../use-keyboard'
|
||||
|
||||
describe('UseKeyboard', () => {
|
||||
it('should work correctly', () => {
|
||||
let code = null
|
||||
const handler = jest.fn().mockImplementation(e => {
|
||||
code = e.keyCode
|
||||
})
|
||||
renderHook(() => useKeyboard(handler, KeyCode.KEY_H))
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: KeyCode.KEY_H }))
|
||||
expect(handler).toBeCalledTimes(1)
|
||||
expect(code).toEqual(KeyCode.KEY_H)
|
||||
})
|
||||
|
||||
it('should not trigger handler', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
renderHook(() => useKeyboard(handler, [KeyCode.KEY_0]))
|
||||
const event = new KeyboardEvent('keydown', { keyCode: KeyCode.KEY_1 })
|
||||
document.dispatchEvent(event)
|
||||
expect(handler).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('should trigger with command key', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
renderHook(() => useKeyboard(handler, [KeyCode.KEY_A, KeyMod.Shift]))
|
||||
const event = new KeyboardEvent('keydown', { keyCode: KeyCode.KEY_A })
|
||||
document.dispatchEvent(event)
|
||||
expect(handler).not.toBeCalled()
|
||||
const event2 = new KeyboardEvent('keydown', {
|
||||
keyCode: KeyCode.KEY_A,
|
||||
shiftKey: true,
|
||||
})
|
||||
document.dispatchEvent(event2)
|
||||
expect(handler).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should ignore command when code does not exist', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
renderHook(() => useKeyboard(handler, [KeyCode.KEY_A, 12345]))
|
||||
const event = new KeyboardEvent('keydown', { keyCode: KeyCode.KEY_A })
|
||||
document.dispatchEvent(event)
|
||||
expect(handler).toBeCalled()
|
||||
})
|
||||
|
||||
it('should work with each command', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
renderHook(() =>
|
||||
useKeyboard(handler, [KeyCode.KEY_A, KeyMod.Alt, KeyMod.CtrlCmd, KeyMod.WinCtrl]),
|
||||
)
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
keyCode: KeyCode.KEY_A,
|
||||
}),
|
||||
)
|
||||
expect(handler).not.toBeCalled()
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
keyCode: KeyCode.KEY_A,
|
||||
altKey: true,
|
||||
}),
|
||||
)
|
||||
expect(handler).not.toBeCalled()
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
keyCode: KeyCode.KEY_A,
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
}),
|
||||
)
|
||||
expect(handler).not.toBeCalled()
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
keyCode: KeyCode.KEY_A,
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
metaKey: true,
|
||||
}),
|
||||
)
|
||||
expect(handler).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should ignore global events', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
renderHook(() => useKeyboard(handler, [KeyCode.KEY_A], { disableGlobalEvent: true }))
|
||||
const event = new KeyboardEvent('keydown', { keyCode: KeyCode.KEY_A })
|
||||
document.dispatchEvent(event)
|
||||
expect(handler).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('should respond to different event types', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
renderHook(() => useKeyboard(handler, [KeyCode.KEY_A], { event: 'keyup' }))
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: KeyCode.KEY_A }))
|
||||
expect(handler).not.toBeCalled()
|
||||
|
||||
document.dispatchEvent(new KeyboardEvent('keypress', { keyCode: KeyCode.KEY_A }))
|
||||
expect(handler).not.toBeCalled()
|
||||
|
||||
document.dispatchEvent(new KeyboardEvent('keyup', { keyCode: KeyCode.KEY_A }))
|
||||
expect(handler).toBeCalled()
|
||||
})
|
||||
|
||||
it('should pass the keyboard events', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
const nativeHandler = jest.fn().mockImplementation(() => {})
|
||||
const { result } = renderHook<void, KeyboardResult>(() =>
|
||||
useKeyboard(handler, KeyCode.Escape),
|
||||
)
|
||||
const wrapper = mount(
|
||||
<div onKeyDown={nativeHandler}>
|
||||
<span id="inner" {...result.current.bindings} />
|
||||
</div>,
|
||||
)
|
||||
const inner = wrapper.find('#inner').at(0)
|
||||
act(() => {
|
||||
inner.simulate('keyup', {
|
||||
keyCode: KeyCode.Escape,
|
||||
})
|
||||
})
|
||||
expect(handler).not.toBeCalled()
|
||||
expect(nativeHandler).not.toBeCalled()
|
||||
act(() => {
|
||||
inner.simulate('keydown', {
|
||||
keyCode: KeyCode.Escape,
|
||||
})
|
||||
})
|
||||
expect(handler).toBeCalled()
|
||||
expect(nativeHandler).toBeCalled()
|
||||
})
|
||||
|
||||
it('should prevent default events', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
const nativeHandler = jest.fn().mockImplementation(() => {})
|
||||
const { result } = renderHook<void, KeyboardResult>(() =>
|
||||
useKeyboard(handler, KeyCode.Escape, {
|
||||
disableGlobalEvent: true,
|
||||
stopPropagation: true,
|
||||
}),
|
||||
)
|
||||
const wrapper = mount(
|
||||
<div onKeyDown={nativeHandler}>
|
||||
<span id="inner" {...result.current.bindings} />
|
||||
</div>,
|
||||
)
|
||||
const inner = wrapper.find('#inner').at(0)
|
||||
act(() => {
|
||||
inner.simulate('keydown', {
|
||||
keyCode: KeyCode.Escape,
|
||||
})
|
||||
})
|
||||
expect(handler).toBeCalled()
|
||||
expect(nativeHandler).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('should trigger capture event', () => {
|
||||
const handler = jest.fn().mockImplementation(() => {})
|
||||
const { result } = renderHook<void, KeyboardResult>(() =>
|
||||
useKeyboard(handler, KeyCode.Escape, { capture: true, disableGlobalEvent: true }),
|
||||
)
|
||||
const wrapper = mount(
|
||||
<div onKeyDownCapture={result.current.bindings.onKeyDownCapture}>
|
||||
<span id="inner" />
|
||||
</div>,
|
||||
)
|
||||
const inner = wrapper.find('#inner').at(0)
|
||||
act(() => {
|
||||
inner.simulate('keydown', {
|
||||
keyCode: KeyCode.Escape,
|
||||
})
|
||||
})
|
||||
expect(handler).toBeCalled()
|
||||
})
|
||||
})
|
||||
94
components/use-keyboard/codes.ts
Normal file
94
components/use-keyboard/codes.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* KeyBinding Codes
|
||||
* The content of this file is based on the design of the open source project "microsoft/vscode",
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* We inherit the KeyMod values from "microsoft/vscode",
|
||||
* but use the Browser's KeyboardEvent event implementation, and all values are used only as identification.
|
||||
*/
|
||||
|
||||
export enum KeyCode {
|
||||
Unknown = 0,
|
||||
Backspace = 8,
|
||||
Tab = 9,
|
||||
Enter = 13,
|
||||
Shift = 16,
|
||||
Ctrl = 17,
|
||||
Alt = 18,
|
||||
PauseBreak = 19,
|
||||
CapsLock = 20,
|
||||
Escape = 27,
|
||||
Space = 32,
|
||||
PageUp = 33,
|
||||
PageDown = 34,
|
||||
End = 35,
|
||||
Home = 36,
|
||||
LeftArrow = 37,
|
||||
UpArrow = 38,
|
||||
RightArrow = 39,
|
||||
DownArrow = 40,
|
||||
Insert = 45,
|
||||
Delete = 46,
|
||||
KEY_0 = 48,
|
||||
KEY_1 = 49,
|
||||
KEY_2 = 50,
|
||||
KEY_3 = 51,
|
||||
KEY_4 = 52,
|
||||
KEY_5 = 53,
|
||||
KEY_6 = 54,
|
||||
KEY_7 = 55,
|
||||
KEY_8 = 56,
|
||||
KEY_9 = 57,
|
||||
KEY_A = 65,
|
||||
KEY_B = 66,
|
||||
KEY_C = 67,
|
||||
KEY_D = 68,
|
||||
KEY_E = 69,
|
||||
KEY_F = 70,
|
||||
KEY_G = 71,
|
||||
KEY_H = 72,
|
||||
KEY_I = 73,
|
||||
KEY_J = 74,
|
||||
KEY_K = 75,
|
||||
KEY_L = 76,
|
||||
KEY_M = 77,
|
||||
KEY_N = 78,
|
||||
KEY_O = 79,
|
||||
KEY_P = 80,
|
||||
KEY_Q = 81,
|
||||
KEY_R = 82,
|
||||
KEY_S = 83,
|
||||
KEY_T = 84,
|
||||
KEY_U = 85,
|
||||
KEY_V = 86,
|
||||
KEY_W = 87,
|
||||
KEY_X = 88,
|
||||
KEY_Y = 89,
|
||||
KEY_Z = 90,
|
||||
Meta = 91,
|
||||
F1 = 112,
|
||||
F2 = 113,
|
||||
F3 = 114,
|
||||
F4 = 115,
|
||||
F5 = 116,
|
||||
F6 = 117,
|
||||
F7 = 118,
|
||||
F8 = 119,
|
||||
F9 = 120,
|
||||
F10 = 121,
|
||||
F11 = 122,
|
||||
F12 = 123,
|
||||
NumLock = 144,
|
||||
ScrollLock = 145,
|
||||
Equal = 187,
|
||||
Minus = 189,
|
||||
Backquote = 192,
|
||||
Backslash = 220,
|
||||
}
|
||||
|
||||
export enum KeyMod {
|
||||
CtrlCmd = (1 << 11) >>> 0,
|
||||
Shift = (1 << 10) >>> 0,
|
||||
Alt = (1 << 9) >>> 0,
|
||||
WinCtrl = (1 << 8) >>> 0,
|
||||
}
|
||||
27
components/use-keyboard/helper.ts
Normal file
27
components/use-keyboard/helper.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { isMac } from '../utils/collections'
|
||||
import { KeyMod } from './codes'
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const getCtrlKeysByPlatform = (): Record<string, 'metaKey' | 'ctrlKey'> => {
|
||||
return {
|
||||
CtrlCmd: isMac() ? 'metaKey' : 'ctrlKey',
|
||||
WinCtrl: isMac() ? 'ctrlKey' : 'metaKey',
|
||||
}
|
||||
}
|
||||
|
||||
export const getActiveModMap = (
|
||||
bindings: number[],
|
||||
): Record<keyof typeof KeyMod, boolean> => {
|
||||
const modBindings = bindings.filter((item: number) => !!KeyMod[item])
|
||||
const activeModMap: Record<keyof typeof KeyMod, boolean> = {
|
||||
CtrlCmd: false,
|
||||
Shift: false,
|
||||
Alt: false,
|
||||
WinCtrl: false,
|
||||
}
|
||||
modBindings.forEach(code => {
|
||||
const modKey = KeyMod[code] as keyof typeof KeyMod
|
||||
activeModMap[modKey] = true
|
||||
})
|
||||
return activeModMap
|
||||
}
|
||||
5
components/use-keyboard/index.ts
Normal file
5
components/use-keyboard/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import useKeyboard from './use-keyboard'
|
||||
import { KeyMod, KeyCode } from './codes'
|
||||
|
||||
export default useKeyboard
|
||||
export { KeyMod, KeyCode }
|
||||
90
components/use-keyboard/use-keyboard.ts
Normal file
90
components/use-keyboard/use-keyboard.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { KeyMod } from './codes'
|
||||
import React, { useEffect } from 'react'
|
||||
import { getActiveModMap, getCtrlKeysByPlatform } from './helper'
|
||||
|
||||
export type KeyboardOptions = {
|
||||
disableGlobalEvent?: boolean
|
||||
stopPropagation?: boolean
|
||||
preventDefault?: boolean
|
||||
capture?: boolean
|
||||
event?: 'keydown' | 'keypress' | 'keyup'
|
||||
}
|
||||
|
||||
export type KeyboardResult = {
|
||||
bindings: {
|
||||
onKeyDown: React.KeyboardEventHandler
|
||||
onKeyDownCapture: React.KeyboardEventHandler
|
||||
onKeyPress: React.KeyboardEventHandler
|
||||
onKeyPressCapture: React.KeyboardEventHandler
|
||||
onKeyUp: React.KeyboardEventHandler
|
||||
onKeyUpCapture: React.KeyboardEventHandler
|
||||
}
|
||||
}
|
||||
|
||||
export type UseKeyboardHandler = (event: React.KeyboardEvent | KeyboardEvent) => void
|
||||
|
||||
export type UseKeyboard = (
|
||||
handler: UseKeyboardHandler,
|
||||
keyBindings: Array<number> | number,
|
||||
options?: KeyboardOptions,
|
||||
) => KeyboardResult
|
||||
|
||||
const useKeyboard: UseKeyboard = (handler, keyBindings, options = {}) => {
|
||||
const bindings = Array.isArray(keyBindings) ? (keyBindings as number[]) : [keyBindings]
|
||||
const {
|
||||
disableGlobalEvent = false,
|
||||
capture = false,
|
||||
stopPropagation = false,
|
||||
preventDefault = true,
|
||||
event = 'keydown',
|
||||
} = options
|
||||
const activeModMap = getActiveModMap(bindings)
|
||||
const keyCode = bindings.filter((item: number) => !KeyMod[item])[0]
|
||||
const { CtrlCmd, WinCtrl } = getCtrlKeysByPlatform()
|
||||
|
||||
const eventHandler = (event: React.KeyboardEvent | KeyboardEvent) => {
|
||||
if (activeModMap.Shift && !event.shiftKey) return
|
||||
if (activeModMap.Alt && !event.altKey) return
|
||||
if (activeModMap.CtrlCmd && !event[CtrlCmd]) return
|
||||
if (activeModMap.WinCtrl && !event[WinCtrl]) return
|
||||
if (keyCode && event.keyCode !== keyCode) return
|
||||
if (stopPropagation) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
if (preventDefault) {
|
||||
event.preventDefault()
|
||||
}
|
||||
handler && handler(event)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!disableGlobalEvent) {
|
||||
document.addEventListener(event, eventHandler)
|
||||
}
|
||||
return () => {
|
||||
document.removeEventListener(event, eventHandler)
|
||||
}
|
||||
}, [disableGlobalEvent])
|
||||
|
||||
const elementBindingHandler = (
|
||||
elementEventType: 'keydown' | 'keypress' | 'keyup',
|
||||
isCapture: boolean = false,
|
||||
) => {
|
||||
if (elementEventType !== event) return () => {}
|
||||
if (isCapture !== capture) return () => {}
|
||||
return (e: React.KeyboardEvent) => eventHandler(e)
|
||||
}
|
||||
|
||||
return {
|
||||
bindings: {
|
||||
onKeyDown: elementBindingHandler('keydown'),
|
||||
onKeyDownCapture: elementBindingHandler('keydown', true),
|
||||
onKeyPress: elementBindingHandler('keypress'),
|
||||
onKeyPressCapture: elementBindingHandler('keypress', true),
|
||||
onKeyUp: elementBindingHandler('keyup'),
|
||||
onKeyUpCapture: elementBindingHandler('keyup', true),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default useKeyboard
|
||||
@@ -138,3 +138,14 @@ export const isChildElement = (
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const isBrowser = (): boolean => {
|
||||
return Boolean(
|
||||
typeof window !== 'undefined' && window.document && window.document.createElement,
|
||||
)
|
||||
}
|
||||
|
||||
export const isMac = (): boolean => {
|
||||
if (!isBrowser()) return false
|
||||
return navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const isBrowser = (): boolean => {
|
||||
return Boolean(
|
||||
typeof window !== 'undefined' && window.document && window.document.createElement,
|
||||
)
|
||||
}
|
||||
import { isBrowser } from './collections'
|
||||
|
||||
export type SSRState = {
|
||||
isBrowser: boolean
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
81
pages/en-us/components/use-keyboard.mdx
Normal file
81
pages/en-us/components/use-keyboard.mdx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Layout, Playground, Attributes } from 'lib/components'
|
||||
import { useKeyboard, KeyCode, KeyMod, Keyboard, Input, Link } from 'components'
|
||||
|
||||
export const meta = {
|
||||
title: 'use-keyboard',
|
||||
group: 'Utils',
|
||||
}
|
||||
|
||||
## Use Keyboard
|
||||
|
||||
React Hooks for listen to multiple keyboard events.
|
||||
|
||||
This is custom React Hooks, you need to follow the <Link target="_blank" color href="https://reactjs.org/docs/hooks-rules.html">Basic Rules</Link> when you use it.
|
||||
|
||||
<Playground
|
||||
desc="Global keyboard events."
|
||||
scope={{ useKeyboard, KeyCode, KeyMod, Keyboard }}
|
||||
code={`
|
||||
() => {
|
||||
useKeyboard(
|
||||
() => alert('save success!'),
|
||||
[KeyCode.KEY_S, KeyMod.CtrlCmd]
|
||||
)
|
||||
return <div>Press <Keyboard command>S</Keyboard> to save.</div>
|
||||
}
|
||||
`}
|
||||
/>
|
||||
|
||||
<Playground
|
||||
title="Element Event"
|
||||
desc="keyboard events listening on elements."
|
||||
scope={{ useKeyboard, KeyCode, KeyMod, Keyboard, Input }}
|
||||
code={`
|
||||
() => {
|
||||
const { bindings } = useKeyboard(
|
||||
() => alert('A is not allowed'),
|
||||
[KeyCode.KEY_A],
|
||||
{ disableGlobalEvent: true },
|
||||
)
|
||||
return (
|
||||
<div>
|
||||
<p>Keyboard events are triggered only when the element is activated.</p>
|
||||
<Input {...bindings} placeholder="Press A" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`}
|
||||
/>
|
||||
|
||||
<Attributes edit="/pages/en-us/components/use-keyboard.mdx">
|
||||
<Attributes.Title>useKeyboard</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type KeyboardOptions = {
|
||||
disableGlobalEvent: boolean,
|
||||
stopPropagation: boolean
|
||||
preventDefault: boolean
|
||||
capture: boolean
|
||||
event: 'keydown' | 'keypress' | 'keyup'
|
||||
}
|
||||
|
||||
const useKeyboard = (
|
||||
handler: (event: React.KeyboardEvent) => void,
|
||||
keyBindings: Array<number> | number,
|
||||
options?: KeyboardOptions,
|
||||
) => void
|
||||
```
|
||||
|
||||
<Attributes.Title>KeyboardOptions</Attributes.Title>
|
||||
|
||||
| Option | Description | Type | Accepted values | Default |
|
||||
| ---------------------- | ----------------------------------- | --------- | -------------------------------- | --------- |
|
||||
| **disableGlobalEvent** | disable global events from document | `boolean` | - | `false` |
|
||||
| **stopPropagation** | stop event Propagation | `boolean` | - | `false` |
|
||||
| **preventDefault** | block the default behavior of event | `boolean` | - | `true` |
|
||||
| **capture** | set event type to "capture" | `boolean` | - | `false` |
|
||||
| **event** | keyboard event type | `string` | `'keydown', 'keypress', 'keyup'` | `keydown` |
|
||||
|
||||
</Attributes>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>
|
||||
81
pages/zh-cn/components/use-keyboard.mdx
Normal file
81
pages/zh-cn/components/use-keyboard.mdx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Layout, Playground, Attributes } from 'lib/components'
|
||||
import { useKeyboard, KeyCode, KeyMod, Keyboard, Input, Link } from 'components'
|
||||
|
||||
export const meta = {
|
||||
title: '键盘事件 useKeyboard',
|
||||
group: '工具包',
|
||||
}
|
||||
|
||||
## Use Keyboard / 键盘事件
|
||||
|
||||
用户监听多个键盘事件的钩子。
|
||||
|
||||
这是一个自定义的 React Hooks,你需要在使用时遵循 <Link target="_blank" color href="https://reactjs.org/docs/hooks-rules.html">钩子的基础规则</Link>。
|
||||
|
||||
<Playground
|
||||
desc="全局的键盘事件。"
|
||||
scope={{ useKeyboard, KeyCode, KeyMod, Keyboard }}
|
||||
code={`
|
||||
() => {
|
||||
useKeyboard(
|
||||
() => alert('保存成功!'),
|
||||
[KeyCode.KEY_S, KeyMod.CtrlCmd]
|
||||
)
|
||||
return <div>按下 <Keyboard command>S</Keyboard> 以保存。</div>
|
||||
}
|
||||
`}
|
||||
/>
|
||||
|
||||
<Playground
|
||||
title="元素事件"
|
||||
desc="只在指定元素上监听元素事件。"
|
||||
scope={{ useKeyboard, KeyCode, KeyMod, Keyboard, Input }}
|
||||
code={`
|
||||
() => {
|
||||
const { bindings } = useKeyboard(
|
||||
() => alert('A 是不被允许的'),
|
||||
[KeyCode.KEY_A],
|
||||
{ disableGlobalEvent: true },
|
||||
)
|
||||
return (
|
||||
<div>
|
||||
<p>键盘事件只在输入框被触发后才会响应。</p>
|
||||
<Input {...bindings} placeholder="输入 A" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`}
|
||||
/>
|
||||
|
||||
<Attributes edit="/pages/en-us/components/use-keyboard.mdx">
|
||||
<Attributes.Title>useKeyboard</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type KeyboardOptions = {
|
||||
disableGlobalEvent: boolean,
|
||||
stopPropagation: boolean
|
||||
preventDefault: boolean
|
||||
capture: boolean
|
||||
event: 'keydown' | 'keypress' | 'keyup'
|
||||
}
|
||||
|
||||
const useKeyboard = (
|
||||
handler: (event: React.KeyboardEvent) => void,
|
||||
keyBindings: Array<number> | number,
|
||||
options?: KeyboardOptions,
|
||||
) => void
|
||||
```
|
||||
|
||||
<Attributes.Title>KeyboardOptions</Attributes.Title>
|
||||
|
||||
| 参数 | 描述 | 类型 | 推荐值 | 默认 |
|
||||
| ---------------------- | -------------------------------- | --------- | -------------------------------- | --------- |
|
||||
| **disableGlobalEvent** | 禁止监听来自 Document 的全局事件 | `boolean` | - | `false` |
|
||||
| **stopPropagation** | 停止事件传播 | `boolean` | - | `false` |
|
||||
| **preventDefault** | 阻止事件的默认行为 | `boolean` | - | `true` |
|
||||
| **capture** | 设置事件类型为捕获 | `boolean` | - | `false` |
|
||||
| **event** | 键盘事件的类型 | `string` | `'keydown', 'keypress', 'keyup'` | `keydown` |
|
||||
|
||||
</Attributes>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>
|
||||
Reference in New Issue
Block a user