对动态表单编辑器指定dom绑定快捷键不生效,原来缺少了这个属性

在这里插入图片描述

前言

开发低代码动态表单设计器过程中,为了方便快速对表单进行操作,使用了快捷键的方式对表单进行复制、粘贴、剪切、上移、下移等操作.

开发之初,把快捷键直接绑定到document上,但是出现了问题,如果对表单内容进行操作,会触发全局绑定到快捷键操作,如,我使用ctrl + c对表单内的内容进行复制,但是同时也会触发对表单组件的复制,如果全局绑定的事件使用了preventDefault,对表单内容复制不会生效.

第一版

快捷键的操作,就是对指定dom绑定keyupkeydown事件,第一版开发的时候,是直接监听这两个事件对页面进行监听.

通过鼠标键盘下对应的keycode进行判断用户按下的是哪个键进行对应的逻辑操作

第一版快捷键开发是通过枚举的方式把需要keycode枚举出来进行对于操作,但是劣势很明显,该版本只兼容了windows电脑,不支持mac电脑,如果还要支持更多的快捷键的话,局限性很大,维护性很差,开发工作量也很大,所以想成为一个懒惰的程序员,只能寻找开源库了.

import store from '@/store/index'
const CTRL = 17, 
CKEY = 67, // 复制
VKEY = 86, // 粘贴
ZKEY = 90, // 回退
DELETEKEY = 46, // 删除
TOPKEY = 38, // 上移
BOTTOMKEY = 40,  // 下移
XKEY = 88, // 裁剪
EKEY = 69; // 清空画布

const baseMap:any = {
    [CKEY]: copy,
    [VKEY]: paste,
    [TOPKEY]: onTop,
    [BOTTOMKEY]: onBottom,
    [XKEY]: cut,
    [EKEY]: clearCanvas
}

function clearCanvas(){
    store.commit('clear')
}

export function copy(){
    store.commit('copy')
}

export function paste(){
    store.commit('paste')
}

export function cut(){
    store.commit('copy')
    store.commit('delete')
}

export function onDelete(){
    store.commit('delete')
}

export function onTop(){
    store.commit('onTop')
}

export function onBottom(){
    store.commit('onBottom')
}



let isCtrlDown = false; // 默认没有按住ctrl

export function listenGlobalKeyDown(){
    window.onkeydown = (e:any) => {
        if(e.keyCode === CTRL){
            isCtrlDown = true
        }else if(!isCtrlDown){
            if(e.keyCode === DELETEKEY){
                onDelete()
            }else if(e.keyCode === TOPKEY){
                store.commit('moveTop')
            }else if(e.keyCode === BOTTOMKEY){
                store.commit('moveBottom')
            }
        }else if(isCtrlDown){
            e.preventDefault()
            baseMap[e.keyCode] && baseMap[e.keyCode]()
        }
    }
    window.onkeyup = (e: any) => {
        if(isCtrlDown && e.keyCode === CTRL){
            isCtrlDown = false
        }
    }
}

重构版本,开源库的使用

在工作摸鱼间隙,逛github,不断搜索快捷键等关键词,功夫不负有心人,找到了两个开源库

keycon

文件大小:169bytes

文档齐全,操作简单,支持mac和windows系统

KeyboardJS

文件大小: 17.2k

文档齐全,操作简单,支持mac和windows系统

选择

做了对比后选择了keycon这个库,因为该库已经能满足我全部需求,同时文件很小,微不足道

使用keycon

我是在表单编辑器初始化完成后,onMounted中对快捷键进行初始化,对需要的快捷键进行设置

  import KeyController from "keycon";
  const keycons:KeyController = new KeyController(dom);
  const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
  const ctrl = isMac ? "meta" : "ctrl";
  keycons
    .keyup("delete", (e) => {
      e.inputEvent.preventDefault();
      list.delete();
    })
    .keyup("backspace", (e) => {
      e.inputEvent.preventDefault();
      list.delete();
    })
    .keydown([ctrl, "c"], (e) => {
      e.inputEvent.preventDefault();
      list.copy();
    })
    .keydown([ctrl, "v"], (e) => {
      e.inputEvent.preventDefault();
      list.paste();
    })
    .keydown([ctrl, "x"], (e) => {
      e.inputEvent.preventDefault();
      list.cut();
    })
    .keydown([ctrl, "up"], (e) => {
      e.inputEvent.preventDefault();
      list.onTop();
    })
    .keydown([ctrl, "down"], (e) => {
      e.inputEvent.preventDefault();
      list.onBottom();
    });
问题1:绑定指定dom不生效

开发时,我对指定区域绑定快捷键操作,但是不生效,如果绑定到body下面,就会生效.

结果不断查阅文档,发现要对指定dom绑定一个属性,tabindex

tabindex定义

tabindex 全局属性 ,表示元素是否可以聚焦,以及是否能用**键盘导航(Tab)**选中

tabindex 有三个值:0,-N(通常是-1),N(正值)

  • tabindex=0,该元素可以用tab键获取焦点

    • 且访问的顺序是按照元素在文档中的顺序来focus,即使采用了浮动改变了页面中显示的顺序,依然是按照html文档中的顺序来定位
  • tabindex<=-1,该元素用tab键获取不到焦点,但是可以通过js获取

    • 这样就便于我们通过js设置上下左右键的响应事件来focus
    • 取值 -1~-999 之间没有区别,但为了可读性和一致性考虑,推荐使用 -1
  • tabindex>=1,该元素可以用tab键获取焦点,而且优先级大于tabindex=0

    • 不过在tabindex>=1时,数字越小,越先定位到;
    • 如果多个元素拥有相同的 tabindex ,他们的相对顺序按照他们在当前DOM中的先后顺序决定

所有在要绑定快捷键的dom增加了该属性就成功了

问题2:必须点击对于的dom快捷键才会生效

完成tabindex后,快捷键的逻辑也能运行了,但是体验不是很好,必须点击对应的区域后快捷键才能使用

发现是点击后,该dom才是聚焦状态,而快捷键绑定的元素必须是聚焦状态才会生效

所以通过监听鼠标的移入移出,进行手动聚焦

  const mouseenterHandler = () => {
        dom?.focus();
  };

  const mouseleaveHandler = () => {
        dom?.blur();
  };
  dom = workspace.value?.$el;
  dom.addEventListener("mouseenter", mouseenterHandler);
  dom.addEventListener("mouseleave", mouseleaveHandler);

可以进行体验: 点此立即体验

希望各位大佬能给个鼓励,感谢!!! 源码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值