js快捷键设置

/* 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);

  

posted @ 2019-10-10 09:29  SharkChilli  阅读(1544)  评论(0编辑  收藏  举报