287 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.2 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 + 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_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 += 'PageUp'
 | |
|           } else if (key === 'PageDown') {
 | |
|             controlKey += 'PageDown'
 | |
|           } 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;
 | |
|   background-color: #fff;
 | |
|   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: #188cff;
 | |
|   box-shadow: 0 0 4px rgba(24, 140, 255, 0.38);
 | |
| }
 | |
| 
 | |
| /* .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>
 |