Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
najiu-admin-template
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
najiu-frontend
najiu-admin-template
Commits
3c3e640d
Commit
3c3e640d
authored
Dec 24, 2020
by
vben
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(hook): add useKeyPress
parent
819bcbe5
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
261 additions
and
82 deletions
+261
-82
useMenuSearch.ts
src/components/Application/src/search/useMenuSearch.ts
+5
-10
useEffect.ts
src/hooks/core/useEffect.ts
+6
-4
useLockFn.ts
src/hooks/core/useLockFn.ts
+19
-0
useModel.ts
src/hooks/core/useModel.ts
+0
-47
useState.ts
src/hooks/core/useState.ts
+58
-0
useToggle.ts
src/hooks/core/useToggle.ts
+0
-20
useKeyPress.ts
src/hooks/event/useKeyPress.ts
+172
-0
useScript.ts
src/hooks/web/useScript.ts
+1
-1
No files found.
src/components/Application/src/search/useMenuSearch.ts
View file @
3c3e640d
import
{
cloneDeep
}
from
'
lodash-es
'
;
import
{
cloneDeep
}
from
'
lodash-es
'
;
import
{
ref
,
onBefore
Unmount
,
onBefore
Mount
,
unref
,
Ref
}
from
'
vue
'
;
import
{
ref
,
onBeforeMount
,
unref
,
Ref
}
from
'
vue
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
getMenus
}
from
'
/@/router/menus
'
;
import
{
getMenus
}
from
'
/@/router/menus
'
;
import
type
{
Menu
}
from
'
/@/router/types
'
;
import
type
{
Menu
}
from
'
/@/router/types
'
;
...
@@ -7,6 +7,7 @@ import { filter, forEach } from '/@/utils/helper/treeHelper';
...
@@ -7,6 +7,7 @@ import { filter, forEach } from '/@/utils/helper/treeHelper';
import
{
useDebounce
}
from
'
/@/hooks/core/useDebounce
'
;
import
{
useDebounce
}
from
'
/@/hooks/core/useDebounce
'
;
import
{
useGo
}
from
'
/@/hooks/web/usePage
'
;
import
{
useGo
}
from
'
/@/hooks/web/usePage
'
;
import
{
useScrollTo
}
from
'
/@/hooks/event/useScrollTo
'
;
import
{
useScrollTo
}
from
'
/@/hooks/event/useScrollTo
'
;
import
{
useKeyPress
}
from
'
/@/hooks/event/useKeyPress
'
;
export
interface
SearchResult
{
export
interface
SearchResult
{
name
:
string
;
name
:
string
;
...
@@ -50,12 +51,6 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
...
@@ -50,12 +51,6 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
forEach
(
menuList
,
(
item
)
=>
{
forEach
(
menuList
,
(
item
)
=>
{
item
.
name
=
t
(
item
.
name
);
item
.
name
=
t
(
item
.
name
);
});
});
document
.
addEventListener
(
'
keydown
'
,
registerKeyDown
);
});
onBeforeUnmount
(()
=>
{
document
.
removeEventListener
(
'
keydown
'
,
registerKeyDown
);
});
});
function
search
(
e
:
ChangeEvent
)
{
function
search
(
e
:
ChangeEvent
)
{
...
@@ -151,8 +146,8 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
...
@@ -151,8 +146,8 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
emit
(
'
close
'
);
emit
(
'
close
'
);
}
}
function
registerKeyDown
(
e
:
KeyboardEvent
)
{
useKeyPress
([
'
enter
'
,
'
up
'
,
'
down
'
],
(
events
)
=>
{
const
keyCode
=
window
.
event
?
e
.
keyCode
:
e
.
which
;
const
keyCode
=
events
.
keyCode
;
switch
(
keyCode
)
{
switch
(
keyCode
)
{
case
KeyCodeEnum
.
UP
:
case
KeyCodeEnum
.
UP
:
handleUp
();
handleUp
();
...
@@ -167,7 +162,7 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
...
@@ -167,7 +162,7 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
handleClose
();
handleClose
();
break
;
break
;
}
}
}
}
);
return
{
handleSearch
,
searchResult
,
keyword
,
activeIndex
,
handleMouseenter
,
handleEnter
};
return
{
handleSearch
,
searchResult
,
keyword
,
activeIndex
,
handleMouseenter
,
handleEnter
};
}
}
src/hooks/core/useEffect.ts
View file @
3c3e640d
import
{
WatchOptions
}
from
'
vue
'
;
import
{
watch
}
from
'
vue
'
;
import
{
watch
}
from
'
vue
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
export
const
useEffect
=
(
effectHandler
:
Fn
,
dependencies
:
any
[])
=>
{
export
function
useEffect
<
T
extends
any
=
any
>
(
effectHandler
:
(
deps
:
T
[],
prevDeps
?:
T
[])
=>
()
=>
void
,
dependencies
:
T
[]
)
{
return
watch
(
return
watch
(
dependencies
,
dependencies
,
(
changedDependencies
,
prevDependencies
,
onCleanUp
)
=>
{
(
changedDependencies
,
prevDependencies
,
onCleanUp
)
=>
{
...
@@ -11,6 +13,6 @@ export const useEffect = (effectHandler: Fn, dependencies: any[]) => {
...
@@ -11,6 +13,6 @@ export const useEffect = (effectHandler: Fn, dependencies: any[]) => {
onCleanUp
(
effectCleaner
);
onCleanUp
(
effectCleaner
);
}
}
},
},
{
immediate
:
true
,
deep
:
true
}
as
WatchOptions
{
immediate
:
true
,
deep
:
true
}
);
);
}
;
}
src/hooks/core/useLockFn.ts
0 → 100644
View file @
3c3e640d
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
;
}
};
}
src/hooks/core/useModel.ts
deleted
100644 → 0
View file @
819bcbe5
import
{
toRef
,
Ref
,
reactive
,
customRef
,
SetupContext
,
watch
,
UnwrapRef
}
from
'
vue
'
;
export
type
ModelProps
<
U
>
=
Readonly
<
{
[
props
:
string
]:
any
}
&
{
modelValue
?:
U
;
}
>
;
export
function
useModel
<
T
>
(
props
:
ModelProps
<
T
>
,
context
:
SetupContext
,
callback
?:
(
val
:
T
|
undefined
,
internalState
:
{
value
:
UnwrapRef
<
T
|
undefined
>
})
=>
any
)
{
const
outerModel
:
Ref
<
T
|
undefined
>
=
toRef
(
props
,
'
modelValue
'
);
const
internalState
=
reactive
({
value
:
props
.
modelValue
,
});
const
internalModel
=
customRef
<
UnwrapRef
<
T
>
|
undefined
>
((
track
,
trigger
)
=>
{
return
{
get
()
{
track
();
return
internalState
.
value
;
},
set
(
newVal
)
{
if
(
internalState
.
value
===
newVal
)
return
;
internalState
.
value
=
newVal
;
context
.
emit
(
'
update:modelValue
'
,
newVal
);
trigger
();
},
};
});
watch
(
outerModel
,
(
val
,
oldVal
)
=>
{
if
(
val
===
oldVal
||
val
===
internalState
.
value
)
return
;
if
(
callback
)
{
callback
(
val
,
internalState
);
return
;
}
internalState
.
value
=
val
as
UnwrapRef
<
T
>
|
undefined
;
});
return
{
internalState
,
internalModel
,
};
}
src/hooks/core/useState.ts
0 → 100644
View file @
3c3e640d
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
];
}
}
src/hooks/core/useToggle.ts
deleted
100644 → 0
View file @
819bcbe5
import
{
ref
,
watch
,
Ref
,
SetupContext
}
from
'
vue
'
;
export
function
useToggle
(
internalModel
:
Ref
<
unknown
>
,
{
emit
}:
SetupContext
)
{
const
isActive
=
ref
(
!!
internalModel
.
value
);
const
isToggled
=
ref
(
false
);
watch
(
internalModel
,
(
val
)
=>
{
isActive
.
value
=
!!
val
;
});
watch
(
isActive
,
(
value
)
=>
{
!!
value
!==
!!
internalModel
.
value
&&
emit
(
'
onUpdate:modelValue
'
,
value
);
});
function
toggleIt
()
{
isToggled
.
value
=
!
isToggled
.
value
;
}
return
{
isActive
,
toggleIt
,
isToggled
,
};
}
src/hooks/event/useKeyPress.ts
0 → 100644
View file @
3c3e640d
// 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
;
}
src/hooks/web/useScript.ts
View file @
3c3e640d
...
@@ -16,7 +16,7 @@ export function useScript(opts: ScriptOptions) {
...
@@ -16,7 +16,7 @@ export function useScript(opts: ScriptOptions) {
isLoading
.
value
=
false
;
isLoading
.
value
=
false
;
success
.
value
=
true
;
success
.
value
=
true
;
error
.
value
=
false
;
error
.
value
=
false
;
resolve
();
resolve
(
''
);
};
};
script
.
onerror
=
function
(
err
)
{
script
.
onerror
=
function
(
err
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment