/* eslint-disable no-underscore-dangle */ import { each } from 'lodash'; /* 快捷键说明: * 快捷生效模块命名规范: * 1.路由模块-执行this.$hotKey.set('ModuleName', {'F9': ()=>{...callback() }}). ModuleName:'Pos.order' * 2.弹窗模块-执行Dialog name=ModuleName,并传入:hotkeys='callbackObj'. ModuleName:'PosDialog.settlement' * 3.说明-初始设计为键盘的'down'事件,后增加了'up'事件(本不应该使用),所有快捷键均变成了两次触发(down和up)方法会被调用两次, 目前暂不做处理. */ /* 按键字典 * 主键盘: 大写和小写字母, 数字键, 功能键 * 小键盘: 数字键,功能键 * F功能键 * Ctrl-添加'.ctrl', Shift-添加'.alt' */ const KEYCODE = { // 65: "a", 66: "b", 67: "c", 68: "d", 69: "e", 70: "f", 71: "g", // 72: "h", 73: "i", 74: "j", 75: "k", 76: "l", 77: "m", 78: "n", // 79: "o", 80: "p", 81: "q", 82: "r", 83: "s", 84: "t", 85: "u", // 86: "v", 87: "w", 88: "x", 89: "y", 90: "z", 65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H', 73: 'I', 74: 'J', 75: 'K', 76: 'L', 77: 'M', 78: 'N', 79: 'O', 80: 'P', 81: 'Q', 82: 'R', 83: 'S', 84: 'T', 85: 'U', 86: 'V', 87: 'W', 88: 'X', 89: 'Y', 90: 'Z', // 主键盘数字键 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 54: '6', 55: '7', 56: '8', 57: '9', // 小键盘数字键 96: '0', 97: '1', 98: '2', 99: '3', 100: '4', 101: '5', 102: '6', 103: '7', 104: '8', 105: '9', // 功能键 16: 'Shift', 17: 'Ctrl', 18: 'Alt', // 主键盘其他 8: 'BackSpace', 9: 'Tab', 13: 'Enter', 27: 'Esc', 32: 'Space', 33: 'PgUp', 34: 'PgDn', 35: 'End', 36: 'Home', 45: 'Insert', 187: '+', 189: '-', 188: ',', 190: '.', 191: '/', 219: '{', 220: '|', 221: '}', // 小键盘其他 108: 'Enter', 106: '*', 107: '+', 109: '-', 110: '.', 111: '/', // F功能键 112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6', 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12', 38: '↑', 40: '↓', 37: '←', 39: '→', }; /* 快捷键构建类 */ export default class HotKey { constructor() { // 快捷键 存储'执行回调'的对象 this.hotkeys = {}; // 快捷键 模块名称合集 this.modules = []; // this.currentModule = null this.uphotkeys = {}; } static isStop = false stop() { this.constructor.isStop = true; } start() { this.constructor.isStop = false; } // 初始化 init() { document.onkeydown = (event) => { // 获取事件相关属性, 阻止浏览器 BackSpace键,返回url let _vReadOnly; let _vDisabled; const _obj = event.target || event.srcElement; const _t = _obj.type || _obj.getAttribute('type'); _vReadOnly = _obj.readOnly; _vDisabled = _obj.disabled; // 处理undefined值情况 _vReadOnly = (_vReadOnly == undefined) ? false : _vReadOnly; _vDisabled = (_vDisabled == undefined) ? true : _vDisabled; // 事件源类型为密码或单行、多行文本的,并且readOnly属性为true或disabled属性为true的,则退格键失效 const _flag1 = (_t === 'password' || _t === 'text' || _t === 'textarea' || _t === 'number') && (_vReadOnly === true || _vDisabled === true); // 当敲Backspace键时,事件源类型非密码或单行、多行文本的,则退格键失效 const _flag2 = _t !== 'password' && _t !== 'text' && _t !== 'textarea' && _t !== 'number'; // 屏蔽input和textarea的Enter键默认事件, 同时屏蔽button按钮的Enter if (event.keyCode === 13 || (event.keyCode === 13 && $(event.target).is('button'))) { // 但是 恢复 饿了么的弹框组件的确认按钮,所需要的回车键功能恢复,从这加一个判断条件如果是饿么的组件就不屏蔽 if (!$(event.target).hasClass('el-button')) { event.preventDefault(); } } // 屏蔽 F1~F11案件的浏览器默认事件 // 键盘按下 Ctrl + F1~F6 时触发 // BackSpace键入非input或textarea(或状态为readOnly,disabled), 阻止url返回 if ( event.keyCode >= 112 && event.keyCode <= 122 || (event.keyCode >= 112 && event.keyCode <= 117 && event.ctrlKey) || (event.keyCode == 8 && (_flag1 || _flag2)) ) { event.preventDefault(); } // 执行事件触发 this.trigger(event); }; document.onkeyup = (event) => { this.trigger(event, 'up'); }; } // 设置模块名及回调(执行方法) set(moduleName, options, type = 'down') { const index = this.modules.indexOf(moduleName); if (index != -1) { this.modules.splice(index, 1); } this.modules.push(moduleName); if (type === 'down') { if (options) { each(options, (handler, name) => { this.hotkeys[`${moduleName}.${name}`] = handler; }); } } else if (type === 'up') { if (options) { each(options, (handler, name) => { this.uphotkeys[`${moduleName}.${name}`] = handler; }); } } } findMethod(name, callback, moduleName, type = 'down') { if (this.modules.length) { const curModule = this.modules[this.modules.length - 1]; // 最后一个设置热键的界面模块名 const method = `${curModule}.${name}`; let hotkeys = {}; if (type === 'down') { hotkeys = this.hotkeys; } else if (type === 'up') { hotkeys = this.uphotkeys; } if (hotkeys[method]) { callback(hotkeys[method]); } else if (curModule.length) { const modules = curModule.split('.'); modules.pop(); const prevMethod = `${modules.join('.')}.${name}`; if (hotkeys[prevMethod]) { callback(hotkeys[prevMethod]); } } } } // 事件触发方法 trigger(event, type = 'down') { if (this.constructor.isStop || $('.el-message-box__wrapper:visible').length) { return; } this.findMethod( KEYCODE[event.keyCode] + (event.ctrlKey ? '.ctrl' : '') + (event.altKey ? '.alt' : ''), (handler) => { handler(event); }, null, type, ); } // 移除关闭模块(基于模块名) removeCurrentModule(name) { if (this.modules[this.modules.length - 1] == name) { this.modules.pop(); } if (name.indexOf('AddPayHotkey') != -1) { this.modules.forEach((item, index, arr) => { item == name && arr.splice(index, arr.length - 1); }); } } }
import HotKey from '@/common/js/HotKey'; const VueHotKey = {}; VueHotKey.install = (Vue) => { const VueSelf = Vue; VueSelf.prototype.$hotKey = new HotKey(); }; export default VueHotKey;
import VueHotkey from './vue-hotkey'; Vue.use(VueHotkey);