-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
261 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { ref, unref } from 'vue'; | ||
|
||
export function useLockFn<P extends any[] = any[], V extends any = any>( | ||
fn: (...args: P) => Promise<V> | ||
) { | ||
const lockRef = ref(false); | ||
return async function (...args: P) { | ||
if (unref(lockRef)) return; | ||
lockRef.value = true; | ||
try { | ||
const ret = await fn(...args); | ||
lockRef.value = false; | ||
return ret; | ||
} catch (e) { | ||
lockRef.value = false; | ||
throw e; | ||
} | ||
}; | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { isObject } from '@vue/shared'; | ||
import { reactive, Ref, ref, readonly } from 'vue'; | ||
import { isFunction } from '/@/utils/is'; | ||
|
||
type State<T> = ((s: T) => T) | T; | ||
type Dispatch<T> = (t: T) => void; | ||
|
||
type DispatchState<T> = Dispatch<State<T>>; | ||
|
||
type ResultState<T> = Readonly<Ref<T>>; | ||
|
||
export function useState<T extends undefined>( | ||
initialState: (() => T) | T | ||
): [ResultState<T>, DispatchState<T>]; | ||
|
||
export function useState<T extends null>( | ||
initialState: (() => T) | T | ||
): [ResultState<T>, DispatchState<T>]; | ||
|
||
export function useState<T extends boolean>( | ||
initialState: (() => T) | T | ||
): [ResultState<boolean>, DispatchState<boolean>]; | ||
|
||
export function useState<T extends string>( | ||
initialState: (() => T) | T | ||
): [ResultState<string>, DispatchState<string>]; | ||
|
||
export function useState<T extends number>( | ||
initialState: (() => T) | T | ||
): [ResultState<number>, DispatchState<number>]; | ||
|
||
export function useState<T extends object>( | ||
initialState: (() => T) | T | ||
): [Readonly<T>, DispatchState<T>]; | ||
|
||
export function useState<T extends any>( | ||
initialState: (() => T) | T | ||
): [Readonly<T>, DispatchState<T>]; | ||
|
||
export function useState<T>(initialState: (() => T) | T): [ResultState<T> | T, DispatchState<T>] { | ||
if (isFunction(initialState)) { | ||
initialState = (initialState as Fn)(); | ||
} | ||
|
||
if (isObject(initialState)) { | ||
const state = reactive({ data: initialState }) as any; | ||
const setState = (newState: T) => { | ||
state.data = newState; | ||
}; | ||
return [readonly(state), setState]; | ||
} else { | ||
const state = ref(initialState) as any; | ||
const setState = (newState: T) => { | ||
state.value = newState; | ||
}; | ||
return [readonly(state), setState]; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
// https://ahooks.js.org/zh-CN/hooks/dom/use-key-press | ||
|
||
import type { Ref } from 'vue'; | ||
import { onBeforeUnmount, onMounted, unref } from 'vue'; | ||
import { noop } from '/@/utils'; | ||
import { isFunction, isString, isNumber, isArray } from '/@/utils/is'; | ||
|
||
export type KeyPredicate = (event: KeyboardEvent) => boolean; | ||
export type keyType = KeyboardEvent['keyCode'] | KeyboardEvent['key']; | ||
export type KeyFilter = keyType | keyType[] | ((event: KeyboardEvent) => boolean); | ||
export type EventHandler = (event: KeyboardEvent) => void; | ||
|
||
export type keyEvent = 'keydown' | 'keyup'; | ||
|
||
export type TargetElement = HTMLElement | Element | Document | Window; | ||
export type Target = Ref<TargetElement>; | ||
|
||
export type EventOption = { | ||
events?: keyEvent[]; | ||
target?: Target; | ||
}; | ||
|
||
const defaultEvents: keyEvent[] = ['keydown']; | ||
|
||
// 键盘事件 keyCode 别名 | ||
const aliasKeyCodeMap: Record<string, number | number[]> = { | ||
esc: 27, | ||
tab: 9, | ||
enter: 13, | ||
space: 32, | ||
up: 38, | ||
left: 37, | ||
right: 39, | ||
down: 40, | ||
delete: [8, 46], | ||
}; | ||
|
||
// 键盘事件 key 别名 | ||
const aliasKeyMap: Record<string, string | string[]> = { | ||
esc: 'Escape', | ||
tab: 'Tab', | ||
enter: 'Enter', | ||
space: ' ', | ||
// IE11 uses key names without `Arrow` prefix for arrow keys. | ||
up: ['Up', 'ArrowUp'], | ||
left: ['Left', 'ArrowLeft'], | ||
right: ['Right', 'ArrowRight'], | ||
down: ['Down', 'ArrowDown'], | ||
delete: ['Backspace', 'Delete'], | ||
}; | ||
|
||
// 修饰键 | ||
const modifierKey: Record<string, (event: KeyboardEvent) => boolean> = { | ||
ctrl: (event: KeyboardEvent) => event.ctrlKey, | ||
shift: (event: KeyboardEvent) => event.shiftKey, | ||
alt: (event: KeyboardEvent) => event.altKey, | ||
meta: (event: KeyboardEvent) => event.metaKey, | ||
}; | ||
|
||
/** | ||
* 判断按键是否激活 | ||
* @param [event: KeyboardEvent]键盘事件 | ||
* @param [keyFilter: any] 当前键 | ||
* @returns Boolean | ||
*/ | ||
function genFilterKey(event: any, keyFilter: any) { | ||
// 浏览器自动补全 input 的时候,会触发 keyDown、keyUp 事件,但此时 event.key 等为空 | ||
if (!event.key) { | ||
return false; | ||
} | ||
|
||
// 数字类型直接匹配事件的 keyCode | ||
if (isNumber(keyFilter)) { | ||
return event.keyCode === keyFilter; | ||
} | ||
// 字符串依次判断是否有组合键 | ||
const genArr = keyFilter.split('.'); | ||
let genLen = 0; | ||
for (const key of genArr) { | ||
// 组合键 | ||
const genModifier = modifierKey[key]; | ||
// key 别名 | ||
const aliasKey = aliasKeyMap[key]; | ||
// keyCode 别名 | ||
const aliasKeyCode = aliasKeyCodeMap[key]; | ||
/** | ||
* 满足以上规则 | ||
* 1. 自定义组合键别名 | ||
* 2. 自定义 key 别名 | ||
* 3. 自定义 keyCode 别名 | ||
* 4. 匹配 key 或 keyCode | ||
*/ | ||
if ( | ||
(genModifier && genModifier(event)) || | ||
(aliasKey && isArray(aliasKey) ? aliasKey.includes(event.key) : aliasKey === event.key) || | ||
(aliasKeyCode && isArray(aliasKeyCode) | ||
? aliasKeyCode.includes(event.keyCode) | ||
: aliasKeyCode === event.keyCode) || | ||
event.key.toUpperCase() === key.toUpperCase() | ||
) { | ||
genLen++; | ||
} | ||
} | ||
return genLen === genArr.length; | ||
} | ||
|
||
/** | ||
* 键盘输入预处理方法 | ||
*/ | ||
function genKeyFormat(keyFilter: any): KeyPredicate { | ||
if (isFunction(keyFilter)) { | ||
return keyFilter; | ||
} | ||
if (isString(keyFilter) || isNumber(keyFilter)) { | ||
return (event: KeyboardEvent) => genFilterKey(event, keyFilter); | ||
} | ||
if (isArray(keyFilter)) { | ||
return (event: KeyboardEvent) => keyFilter.some((item: any) => genFilterKey(event, item)); | ||
} | ||
return keyFilter ? () => true : () => false; | ||
} | ||
|
||
export function useKeyPress( | ||
keyFilter: KeyFilter, | ||
eventHandler: EventHandler = noop, | ||
option: EventOption = {} | ||
) { | ||
const { events = defaultEvents, target } = option; | ||
|
||
let el: TargetElement | null | undefined; | ||
|
||
function handler(event: any) { | ||
const genGuard: KeyPredicate = genKeyFormat(keyFilter); | ||
if (genGuard(event)) { | ||
return eventHandler(event); | ||
} | ||
} | ||
|
||
onMounted(() => { | ||
el = getTargetElement(target, window); | ||
if (!el) return; | ||
|
||
for (const eventName of events) { | ||
el.addEventListener(eventName, handler); | ||
} | ||
}); | ||
|
||
onBeforeUnmount(() => { | ||
if (!el) return; | ||
for (const eventName of events) { | ||
el.removeEventListener(eventName, handler); | ||
} | ||
}); | ||
} | ||
|
||
export function getTargetElement( | ||
target?: Target, | ||
defaultElement?: TargetElement | ||
): TargetElement | undefined | null { | ||
if (!target) { | ||
return defaultElement; | ||
} | ||
|
||
let targetElement: TargetElement | undefined | null; | ||
|
||
if (isFunction(target)) { | ||
targetElement = target(); | ||
} else { | ||
targetElement = unref(target); | ||
} | ||
return targetElement; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters