285 lines
6.9 KiB
Plaintext
285 lines
6.9 KiB
Plaintext
<template>
|
|
<div
|
|
class="shortcut-key-input"
|
|
:class="{ cursor: focus }"
|
|
:style="$props.style"
|
|
tabindex="0"
|
|
@focus="handleFocus"
|
|
@blur="focus = false"
|
|
@keydown="handleKeydown"
|
|
>
|
|
|
|
<template v-if="key.text">
|
|
|
|
<span>{{ key.text }} <i class="el-icon-circle-close" @click="handleDeleteKey" /></span>
|
|
|
|
</template>
|
|
<div v-else class="placeholder">{{ placeholder }}</div>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
const CODE_NUMBER = Array.from({ length: 10 }, (v, k) => `Digit${k}`)
|
|
const CODE_NUMPAD = Array.from({ length: 10 }, (v, k) => `Numpad${k}`)
|
|
const CODE_ABC = Array.from(
|
|
{ length: 26 },
|
|
(v, k) => `Key${String.fromCharCode(k + 65).toUpperCase()}`
|
|
)
|
|
// const CODE_FN = Array.from({ length: 12 }, (v, k) => `F${k + 1}`)
|
|
const CODE_CONTROL = [
|
|
'Shift',
|
|
'ShiftLeft',
|
|
'ShiftRight',
|
|
'Control',
|
|
'ControlLeft',
|
|
'ControlRight',
|
|
'Alt',
|
|
'AltLeft',
|
|
'AltRight'
|
|
] // ShiftKey Control(Ctrl) Alt
|
|
const CODE_OTHER = [
|
|
'ArrowRight',
|
|
'ArrowLeft',
|
|
'ArrowUp',
|
|
'ArrowDown',
|
|
'PageUp',
|
|
'PageDown',
|
|
'Equal',
|
|
'Minus',
|
|
'Space'
|
|
]
|
|
export default {
|
|
name: 'HotKeyInput',
|
|
props: {
|
|
hotkey: {
|
|
type: Object,
|
|
required: true
|
|
},
|
|
// 校验函数 判断是否允许显示快捷键
|
|
verify: {
|
|
type: Function,
|
|
default: () => true
|
|
},
|
|
hotkeyId: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// 快捷键使用范围
|
|
range: {
|
|
type: Array,
|
|
default: () => ['NUMBER', 'NUMPAD', 'ABC', 'OTHER']
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
focus: false,
|
|
key: { controlKey: '', text: '' },
|
|
|
|
keyRange: []
|
|
}
|
|
},
|
|
watch: {
|
|
key: {
|
|
handler: function(keyObj) {
|
|
if (keyObj.controlKey) this.focus = false
|
|
this.$emit('update:hotkey', this.key)
|
|
},
|
|
immediate: true
|
|
},
|
|
hotkey: {
|
|
handler: function(val) {
|
|
if (!val.text) return
|
|
// var obj = {}
|
|
// const arr = val.text.split('+')
|
|
// const controlKey = {
|
|
// altKey: val.,
|
|
// ctrlKey: arr.includes('Control'),
|
|
// shiftKey: arr.includes('Shift'),
|
|
// key: arr[arr.length - 1],
|
|
// code: `Key${arr[arr.length - 1].toUpperCase()}`
|
|
// }
|
|
// obj = {
|
|
// text: arr.reduce((text, item, i) => {
|
|
// if (i) text += '+'
|
|
// if (controlKey.key === item) text += item.toUpperCase()
|
|
// else text += item
|
|
// return text
|
|
// }, ''),
|
|
// controlKey
|
|
// }
|
|
|
|
this.key.text = val.text
|
|
this.key.controlKey = val.controlKey
|
|
},
|
|
immediate: true
|
|
},
|
|
range: {
|
|
handler: function(val) {
|
|
const keyRangeList = {
|
|
NUMBER: CODE_NUMBER,
|
|
NUMPAD: CODE_NUMPAD,
|
|
ABC: CODE_ABC,
|
|
OTHER: CODE_OTHER
|
|
// FN: CODE_FN
|
|
}
|
|
val.forEach((item) => {
|
|
this.keyRange = this.keyRange.concat(
|
|
keyRangeList[item.toUpperCase()]
|
|
)
|
|
})
|
|
},
|
|
immediate: true
|
|
}
|
|
},
|
|
methods: {
|
|
handleFocus() {
|
|
if (!this.key.text) this.focus = true
|
|
},
|
|
handleDeleteKey() {
|
|
this.key.text = ''
|
|
this.key.controlKey = ''
|
|
this.$emit('update:hotkey', this.key)
|
|
},
|
|
handleKeydown(e) {
|
|
console.log(e)
|
|
const { altKey, ctrlKey, shiftKey, key, code } = e
|
|
if (!CODE_CONTROL.includes(key)) {
|
|
if (!this.keyRange.includes(code)) return
|
|
let controlKey = '';
|
|
[
|
|
{ key: altKey, text: 'Alt' },
|
|
{ key: ctrlKey, text: 'Ctrl' },
|
|
{ key: shiftKey, text: 'Shift' }
|
|
].forEach((curKey) => {
|
|
if (curKey.key) {
|
|
if (controlKey) controlKey += '+'
|
|
controlKey += curKey.text
|
|
}
|
|
})
|
|
|
|
if (key) {
|
|
if (controlKey) controlKey += '+'
|
|
if (key === 'ArrowUp') {
|
|
controlKey += '↑'
|
|
} else if (key === 'ArrowDown') {
|
|
controlKey += '↓'
|
|
} else if (key === 'ArrowLeft') {
|
|
controlKey += '←'
|
|
} else if (key === 'ArrowRight') {
|
|
controlKey += '→'
|
|
} else if (key === 'PageUp') {
|
|
controlKey += 'Page Up'
|
|
} else if (key === 'PageDown') {
|
|
controlKey += 'Page Down'
|
|
} else if (key === '+' && shiftKey) {
|
|
controlKey = '+'
|
|
} else if (key === '=' && !shiftKey) {
|
|
controlKey = '='
|
|
} else if (key === '-' && !shiftKey) {
|
|
controlKey = '-'
|
|
} else if (key === ' ' && code === 'Space') {
|
|
controlKey = 'Space'
|
|
} else {
|
|
controlKey += key.toUpperCase()
|
|
}
|
|
}
|
|
this.addHotkey({
|
|
text: controlKey,
|
|
controlKey: { altKey, ctrlKey, shiftKey, key, code }
|
|
})
|
|
}
|
|
e.preventDefault()
|
|
},
|
|
addHotkey(data) {
|
|
data.id = this.hotkeyId
|
|
if (!this.verify(data)) return
|
|
this.key.text = data.text
|
|
this.key.controlKey = data.controlKey
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
@keyframes Blink {
|
|
0% {
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.shortcut-key-input {
|
|
position: relative;
|
|
border: 1px solid #dcdcdc;
|
|
border-radius: 4px;
|
|
color: #333;
|
|
width: 100%;
|
|
height: 32px;
|
|
padding: 2px 0;
|
|
cursor: text;
|
|
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
}
|
|
|
|
.shortcut-key-input:focus {
|
|
border-color: #00D1B2;
|
|
box-shadow: 0 0 4px #00D1B2;
|
|
}
|
|
|
|
/* .shortcut-key-input.cursor::after {
|
|
content: "|";
|
|
animation: Blink 1.2s ease 0s infinite;
|
|
font-size: 18px;
|
|
position: absolute;
|
|
top: 7px;
|
|
left: 8px;
|
|
} */
|
|
|
|
.shortcut-key-input span {
|
|
position: relative;
|
|
display: inline-block;
|
|
box-sizing: border-box;
|
|
|
|
color: #909399;
|
|
padding: 0 22px 0 8px;
|
|
height: 20px;
|
|
font-size: 13px;
|
|
line-height: 20px;
|
|
border-radius: 4px;
|
|
margin: 5px;
|
|
}
|
|
|
|
.shortcut-key-input .placeholder {
|
|
position: absolute;
|
|
top: 5px;
|
|
left: 5px;
|
|
color: #c0c4cc;
|
|
font-size: 13px;
|
|
text-indent: 4px;
|
|
font: 400 13.3333px Arial;
|
|
}
|
|
|
|
.shortcut-key-input span i {
|
|
position: absolute;
|
|
top: 2px;
|
|
right: 4px;
|
|
content: "";
|
|
/* background: url("data:image/svg+xml,%3Csvg class='icon' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M512 64C264.58 64 64 264.58 64 512s200.58 448 448 448 448-200.58 448-448S759.42 64 512 64zm0 832c-212.08 0-384-171.92-384-384s171.92-384 384-384 384 171.92 384 384-171.92 384-384 384z' fill='%23909399'/%3E%3Cpath d='M625.14 353.61L512 466.75 398.86 353.61a32 32 0 0 0-45.25 45.25L466.75 512 353.61 625.14a32 32 0 0 0 45.25 45.25L512 557.25l113.14 113.14a32 32 0 0 0 45.25-45.25L557.25 512l113.14-113.14a32 32 0 0 0-45.25-45.25z' fill='%23909399'/%3E%3C/svg%3E")
|
|
no-repeat center;
|
|
background-size: contain; */
|
|
width: 14px;
|
|
height: 14px;
|
|
transform: scale(0.9);
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.shortcut-key-input span i:hover {
|
|
cursor: pointer;
|
|
opacity: 1;
|
|
}
|
|
</style>
|