|
|
@@ -1,32 +1,29 @@
|
|
|
<template>
|
|
|
<div
|
|
|
- class="shortcut-key-input"
|
|
|
- :class="{ cursor: focus }"
|
|
|
+ class="hot-key-input-component"
|
|
|
+ :class="{ cursor: focus, 'hot-key-input-shark': isShark }"
|
|
|
:style="$props.style"
|
|
|
tabindex="0"
|
|
|
@focus="handleFocus"
|
|
|
@blur="focus = false"
|
|
|
- @keydown="handleKeydown"
|
|
|
+ @keydown.prevent="handleKeydown"
|
|
|
+ :placeholder="list.length ? '' : placeholder"
|
|
|
>
|
|
|
- <template v-if="list.length">
|
|
|
- <template v-for="(item, index) in list">
|
|
|
- <span :key="`${item.text}_${index}`"
|
|
|
- >{{ item.text }} <i @click="handleDeleteKey(index)"></i
|
|
|
- ></span>
|
|
|
- </template>
|
|
|
- </template>
|
|
|
- <div v-else class="placeholder">{{ placeholder }}</div>
|
|
|
+ <div class="hot-item" v-for="(item, index) in list" :key="index">
|
|
|
+ <span class="hot-text">{{ formatItemText(item.text) }} </span>
|
|
|
+ <i class="icon-close" @click="handleDeleteKey(index)"></i>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-const CODE_NUMBER = Array.from({ length: 10 }, (v, k) => `Digit${k + 1}`);
|
|
|
-const CODE_NUMPAD = Array.from({ length: 10 }, (v, k) => `Numpad${k + 1}`);
|
|
|
+const CODE_NUMBER = Array.from({ length: 10 }, (v, k) => `Digit${k + 1}`)
|
|
|
+const CODE_NUMPAD = Array.from({ length: 10 }, (v, k) => `Numpad${k + 1}`)
|
|
|
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_FN = Array.from({ length: 12 }, (v, k) => `F${k + 1}`)
|
|
|
const CODE_CONTROL = [
|
|
|
"Shift",
|
|
|
"ShiftLeft",
|
|
|
@@ -37,15 +34,20 @@ const CODE_CONTROL = [
|
|
|
"Alt",
|
|
|
"AltLeft",
|
|
|
"AltRight",
|
|
|
-]; // ShiftKey Control(Ctrl) Alt
|
|
|
+] // ShiftKey Control(Ctrl) Alt
|
|
|
|
|
|
export default {
|
|
|
name: "HotKeyInput",
|
|
|
props: {
|
|
|
+ type: {
|
|
|
+ type: String,
|
|
|
+ // lowser upper
|
|
|
+ default: ()=> 'defalut'
|
|
|
+ },
|
|
|
// 默认绑定值
|
|
|
// 传入 ['Ctrl+d'] 格式时会自动处理成 [{ text: 'Ctrl+d', controlKey: { altKey: false, ctrlKey: true, shiftKey: false, key: 'd', code: 'KeyD } }]
|
|
|
hotkey: {
|
|
|
- type: Array,
|
|
|
+ type: Array | Object,
|
|
|
required: true,
|
|
|
},
|
|
|
// 校验函数 判断是否允许显示快捷键
|
|
|
@@ -63,6 +65,15 @@ export default {
|
|
|
type: [String, Number],
|
|
|
default: 0,
|
|
|
},
|
|
|
+ // 当max时,再次输入快捷键 - true: 清空后输入,false:无操作
|
|
|
+ reset: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ shake: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
// 快捷键使用范围
|
|
|
range: {
|
|
|
type: Array,
|
|
|
@@ -71,17 +82,30 @@ export default {
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
+ isShark: false,
|
|
|
focus: false,
|
|
|
- list: this.hotkey,
|
|
|
+ hotkeyBackups: this.hotkey || '' ,
|
|
|
+ list: [],
|
|
|
keyRange: [],
|
|
|
- };
|
|
|
+ }
|
|
|
},
|
|
|
watch: {
|
|
|
list: function (list) {
|
|
|
- if (list.length) this.focus = false;
|
|
|
- this.$emit("update:hotkey", this.list);
|
|
|
+ list.length ? (this.focus = false) : (this.focus = true)
|
|
|
+ // .sync修饰符
|
|
|
+ this.$emit(
|
|
|
+ "update:hotkey",
|
|
|
+ this.list.map((item) => {
|
|
|
+ return this.formatItemText(item.text)
|
|
|
+ // if(item.text && this.type != 'default'){
|
|
|
+ // return this.type == 'lowser' ? item.text.toLowerCase():item.text.toUpperCase()
|
|
|
+ // }
|
|
|
+ // return item.text
|
|
|
+ })
|
|
|
+ )
|
|
|
},
|
|
|
- hotkey: {
|
|
|
+
|
|
|
+ hotkeyBackups: {
|
|
|
handler: function (val) {
|
|
|
if (!val.length) return;
|
|
|
const list = [];
|
|
|
@@ -110,70 +134,101 @@ export default {
|
|
|
},
|
|
|
range: {
|
|
|
handler: function (val) {
|
|
|
+ if(val === null){
|
|
|
+ this.keyRange = null
|
|
|
+ return
|
|
|
+ }
|
|
|
const keyRangeList = {
|
|
|
NUMBER: CODE_NUMBER,
|
|
|
NUMPAD: CODE_NUMPAD,
|
|
|
ABC: CODE_ABC,
|
|
|
FN: CODE_FN,
|
|
|
- };
|
|
|
+ }
|
|
|
val.forEach((item) => {
|
|
|
this.keyRange = this.keyRange.concat(
|
|
|
keyRangeList[item.toUpperCase()]
|
|
|
- );
|
|
|
- });
|
|
|
+ )
|
|
|
+ })
|
|
|
},
|
|
|
immediate: true,
|
|
|
},
|
|
|
},
|
|
|
methods: {
|
|
|
+ formatItemText(text){
|
|
|
+ if(text && this.type != 'default'){
|
|
|
+ return this.type == 'lowser' ? text.toLowerCase() : text.toUpperCase()
|
|
|
+ }
|
|
|
+ return text
|
|
|
+ },
|
|
|
handleFocus() {
|
|
|
- if (!this.list.length) this.focus = true;
|
|
|
+ if (!this.list.length) this.focus = true
|
|
|
},
|
|
|
handleDeleteKey(index) {
|
|
|
- this.list.splice(index, 1);
|
|
|
+ this.list.splice(index, 1)
|
|
|
},
|
|
|
handleKeydown(e) {
|
|
|
- const { altKey, ctrlKey, shiftKey, key, code } = e;
|
|
|
+ console.log('e: ',e)
|
|
|
+ e.preventDefault()
|
|
|
+ e.stopPropagation()
|
|
|
+ const { altKey, ctrlKey, shiftKey, key, code } = e
|
|
|
if (!CODE_CONTROL.includes(key)) {
|
|
|
- if (!this.keyRange.includes(code)) return;
|
|
|
- let controlKey = "";
|
|
|
- [
|
|
|
+ if (this.keyRange !== null && !this.keyRange.includes(code)){
|
|
|
+ this.shakeAction()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let controlKey = ''
|
|
|
+ let temps = [
|
|
|
{ key: altKey, text: "Alt" },
|
|
|
{ key: ctrlKey, text: "Ctrl" },
|
|
|
{ key: shiftKey, text: "Shift" },
|
|
|
- ].forEach((curKey) => {
|
|
|
+ ]
|
|
|
+ temps.forEach((curKey) => {
|
|
|
if (curKey.key) {
|
|
|
- if (controlKey) controlKey += "+";
|
|
|
- controlKey += curKey.text;
|
|
|
+ if (controlKey) controlKey += "+"
|
|
|
+ controlKey += curKey.text
|
|
|
}
|
|
|
- });
|
|
|
+ })
|
|
|
if (key) {
|
|
|
- if (controlKey) controlKey += "+";
|
|
|
- controlKey += key.toUpperCase();
|
|
|
+ if (controlKey) controlKey += "+"
|
|
|
+ controlKey += key.toUpperCase()
|
|
|
}
|
|
|
this.addHotkey({
|
|
|
text: controlKey,
|
|
|
controlKey: { altKey, ctrlKey, shiftKey, key, code },
|
|
|
- });
|
|
|
+ })
|
|
|
}
|
|
|
- e.preventDefault();
|
|
|
},
|
|
|
addHotkey(data) {
|
|
|
- if (this.list.length && this.list.some((item) => data.text === item.text))
|
|
|
- return;
|
|
|
- if (
|
|
|
- this.list.length &&
|
|
|
- this.list.length.toString() === this.max.toString()
|
|
|
- )
|
|
|
- return;
|
|
|
- if (!this.verify(data)) return;
|
|
|
- this.list.push(data);
|
|
|
+ if (this.list.length) {
|
|
|
+ if (this.list.length.toString() >= this.max.toString()) {
|
|
|
+ if (this.reset) {
|
|
|
+ this.list = []
|
|
|
+ } else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else if (this.list.some((item) => data.text === item.text)) {
|
|
|
+ this.shakeAction()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!this.verify(data)) {
|
|
|
+ this.shakeAction()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.list.push(data)
|
|
|
},
|
|
|
+ shakeAction(){
|
|
|
+ if(this.shake){
|
|
|
+ this.isShark = true
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.isShark = false
|
|
|
+ }, 800)
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
-};
|
|
|
+}
|
|
|
</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
+<style lang="less">
|
|
|
@keyframes Blink {
|
|
|
0% {
|
|
|
opacity: 0;
|
|
|
@@ -183,62 +238,68 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.shortcut-key-input {
|
|
|
- position: relative;
|
|
|
+@keyframes hot-key-input-shake {
|
|
|
+ 0% {
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+ 10%,
|
|
|
+ 20% {
|
|
|
+ transform: scale(0.9) rotate(-1deg);
|
|
|
+ }
|
|
|
+ 30%,
|
|
|
+ 50%,
|
|
|
+ 70%,
|
|
|
+ 90% {
|
|
|
+ transform: scale(1.1) rotate(1deg);
|
|
|
+ }
|
|
|
+ 40%,
|
|
|
+ 60%,
|
|
|
+ 80% {
|
|
|
+ transform: scale(1.1) rotate(-1deg);
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: scale(1) rotate(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.hot-key-input-shark {
|
|
|
+ animation: hot-key-input-shake 0.8s 1 ease-in;
|
|
|
+}
|
|
|
+
|
|
|
+.hot-key-input-component {
|
|
|
+ display: flex;
|
|
|
+ padding: 5px;
|
|
|
border: 1px solid #dcdcdc;
|
|
|
- border-radius: 4px;
|
|
|
background-color: #fff;
|
|
|
color: #333;
|
|
|
- width: 100%;
|
|
|
- height: 40px;
|
|
|
- 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: #188cff;
|
|
|
- box-shadow: 0 0 4px rgba(24, 140, 255, 0.38);
|
|
|
+.hot-key-input-component:before {
|
|
|
+ content: attr(placeholder);
|
|
|
+ color: #afafaf;
|
|
|
}
|
|
|
|
|
|
-.shortcut-key-input.cursor::after {
|
|
|
+.hot-key-input-component.cursor::after {
|
|
|
content: "|";
|
|
|
animation: Blink 1.2s ease 0s infinite;
|
|
|
- font-size: 18px;
|
|
|
position: absolute;
|
|
|
- top: 7px;
|
|
|
- left: 8px;
|
|
|
+ left: 10px;
|
|
|
}
|
|
|
|
|
|
-.shortcut-key-input span {
|
|
|
- position: relative;
|
|
|
- display: inline-block;
|
|
|
- box-sizing: border-box;
|
|
|
+.hot-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
background-color: #f4f4f5;
|
|
|
border-color: #e9e9eb;
|
|
|
color: #909399;
|
|
|
- padding: 0 22px 0 8px;
|
|
|
- height: 28px;
|
|
|
- font-size: 13px;
|
|
|
- line-height: 28px;
|
|
|
- border-radius: 4px;
|
|
|
- margin: 5px;
|
|
|
+ padding: 0 5px;
|
|
|
+ margin-right: 5px;
|
|
|
}
|
|
|
|
|
|
-.shortcut-key-input .placeholder {
|
|
|
- position: absolute;
|
|
|
- top: 12px;
|
|
|
- left: 11px;
|
|
|
- color: #c0c4cc;
|
|
|
- font-size: 13px;
|
|
|
- text-indent: 4px;
|
|
|
- font: 400 13.3333px Arial;
|
|
|
-}
|
|
|
-
|
|
|
-.shortcut-key-input span i {
|
|
|
- position: absolute;
|
|
|
- top: 6px;
|
|
|
- right: 4px;
|
|
|
+.hot-key-input-component .hot-item .icon-close {
|
|
|
+ display: block;
|
|
|
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;
|
|
|
@@ -249,7 +310,7 @@ export default {
|
|
|
opacity: 0.6;
|
|
|
}
|
|
|
|
|
|
-.shortcut-key-input span i:hover {
|
|
|
+.hot-key-input-component .hot-item .icon-close:hover {
|
|
|
cursor: pointer;
|
|
|
opacity: 1;
|
|
|
}
|