全局注册快捷键方案

在低代码系统中,快捷键是很常用的操作,我们如果只对绘图区域注册快捷键,那么焦点不在绘图区域时,就会失去快捷键响应,如果对全局拦截键盘事件,注册快捷键,那么会失去一些本应该交给系统默认快捷键的行为,例如:文本框选后的复制、文本输入框的粘贴等。

所以,设计一个既不与全局快捷键冲突,又可以全局监听的快捷键方案。

适用于 vue ,但是通过简单改造可适用于大部分前端技术栈。

一、定义一个 HotKeyManager 类,在 utils 中 新建 hotkey-manager.ts 文件:

interface IKey {ctrlKey?: booleanshiftKey?: booleanaltKey?: booleanmetaKey?: booleankeyCode: string
}
export interface IKeyBinding {key: IKey | IKey[]action: (...arg) => void
}export class HotKeyManager {keyEvents: IKeyBinding[]constructor(keyEvents: IKeyBinding[]) {this.keyEvents = keyEventsthis.init()}private init() {document.addEventListener('keydown', this.handleAction)}private handleAction = (e: KeyboardEvent) => {// 1、如果在输入框中,不处理。2、如果在外部选中了文字不处理。3、如果元素的 contenteditable 属性为 true ,不处理const selection = window.getSelection()?.toString()if (e.target instanceof HTMLInputElement ||e.target instanceof HTMLTextAreaElement ||(e.target && (e.target as HTMLElement).contentEditable === 'true') ||selection) {return}for (const keyBinding of this.keyEvents) {if (this.isKeyMatch(keyBinding.key, e)) {e.preventDefault() // 如果匹配到快捷键,阻止默认事件keyBinding.action(e)return}}}private isKeyMatch(key: IKey | IKey[], e: KeyboardEvent): boolean {if (Array.isArray(key)) {return key.some((k) => this.isKeyMatch(k, e))}if (key.keyCode === '*') return trueconst {ctrlKey = false,shiftKey = false,altKey = false,metaKey = false,} = keyreturn (ctrlKey === e.ctrlKey &&shiftKey === e.shiftKey &&altKey === e.altKey &&metaKey === e.metaKey &&key.keyCode === e.code)}destroy() {this.keyEvents = []document.removeEventListener('keydown', this.handleAction)}
}

二、注册当前系统使用到的快捷键,因为我这里的命令使用到 pinia 中的方法,所以我定义了一个 hooks,在 hooks 文件夹下新建 hotkey-list.ts 文件:

import type { IKeyBinding } from '@/utils/hotkey-manager'
import globalStore from '@/store/global'
import copyManager from '@/store/copy'
import snapshot from '@/store/snapshot'const { moveShape } = globalStore()export default () => {const keyList: IKeyBinding[] = [{key: [{ keyCode: 'Backspace' }, { keyCode: 'Delete' }],action: () => {// 删除const { deleteComponent } = globalStore()deleteComponent()},},{key: { ctrlKey: true, keyCode: 'KeyC' },action: () => {// 复制当前选中的部件const { copy } = copyManager()copy()},},{key: { ctrlKey: true, keyCode: 'KeyX' },action: () => {// 剪切const { cut } = copyManager()cut()},},{key: { ctrlKey: true, keyCode: 'KeyV' },action: () => {// 粘贴const { paste } = copyManager()paste()},},{key: { ctrlKey: true, keyCode: 'KeyZ' },action: () => {// 撤销const { undo } = snapshot()undo()},},{key: [{ ctrlKey: true, shiftKey: true, keyCode: 'KeyZ' },{ ctrlKey: true, keyCode: 'KeyY' },],action: () => {// 恢复const { redo } = snapshot()redo()},},{key: { ctrlKey: true, keyCode: 'KeyP' },action: () => {// 预览},},{key: { ctrlKey: true, keyCode: 'KeyS' },action: () => {// 保存},},{key: { keyCode: 'ArrowUp' },action: () => {// 上移moveShape({ x: 0, y: -1 })},},{key: { keyCode: 'ArrowUp', shiftKey: true },action: () => {// 上移10pxmoveShape({ x: 0, y: -10 })},},{key: { keyCode: 'ArrowDown' },action: () => {// 下移moveShape({ x: 0, y: 1 })},},{key: { keyCode: 'ArrowDown', shiftKey: true },action: () => {// 下移10pxmoveShape({ x: 0, y: 10 })},},{key: { keyCode: 'ArrowLeft' },action: () => {// 左移moveShape({ x: -1, y: 0 })},},{key: { keyCode: 'ArrowLeft', shiftKey: true },action: () => {// 左移10pxmoveShape({ x: -10, y: 0 })},},{key: { keyCode: 'ArrowRight' },action: () => {// 右移moveShape({ x: 1, y: 0 })},},{key: { keyCode: 'ArrowRight', shiftKey: true },action: () => {// 右移10pxmoveShape({ x: 10, y: 0 })},},]return { keyList }
}

三、实例化使用

import { HotKeyManager } from '@/utils/hotkey-manager'
import useHotKeyList from '@/hooks/hotkey-list'const { keyList } = useHotKeyList()const hotKeyManager = new HotKeyManager(keyList)

如果觉得 hooks 的方式不太方便,也可以改造一下 HotKeyManager 类,通过在 HotKeyManager 实例上注册回调函数的形式获取当前触发的快捷键,然后在实例化的地方执行某些动作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/64030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis篇-1--入门介绍

1、Redis概述 ‌Redis(Remote Dictionary Server),全称为远程字典服务。‌是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。 Redis提供了多种数据类型的存储,来适应不同场景下的存储需…

antdv-<a-button>中属性的使用

UI组件库(User Interface Component Library)是一种预先构建好的、可重用的用户界面元素集合,旨在帮助开发者更快速、更简便地构建用户界面。这些组件通常包括按钮、表单、导航栏、模态框等,能够提供一致的外观和交互风格&#xf…

简单的多网卡选择指定网卡ip注册

简单的多网卡选择指定网卡ip注册 我们公司服务器上面有多个网卡,多网卡则本地ip有多个ip,我们启动服务的时候需要选定他特定的ip,我们服务需要特定的ip进行注册,才能进行正常的通讯功能,我们需要使用如下配置进行特定ip选择&…

鸿蒙NEXT开发案例:颜文字搜索器

【引言】 本文将介绍一个名为“颜文字搜索器”的开发案例,该应用是基于鸿蒙NEXT平台构建的,旨在帮助用户快速查找和使用各种风格的表情符号。通过本案例的学习,读者可以了解如何在鸿蒙平台上进行数据处理、UI设计以及交互逻辑的实现。 【环…

快速部署一套K8s集群-v1.28

快速部署一套K8s集群-v1.28 1.前置知识点 1.1 生产环境可部署Kubernetes集群的两种方式 目前生产部署Kubernetes集群主要有两种方式: kubeadmKubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。 二进制包从github下载发行版的二进…

【硬件测试】基于FPGA的4ASK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.Verilog核心程序 4.开发板使用说明和如何移植不同的开发板 5.完整算法代码文件获得 1.算法仿真效果 本文是之前写的文章: 《基于FPGA的4ASK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR》 的…

用友U8+ API接口使用教程

前言 U8和其他的公开的开放API接口有一些差异,他是需要先对接的到代理服务器,通过代理服务器进行对接,所以只要保证U8能上网就能对接,和畅捷通T的模式有点类似 流程: 注册成为开发者(用于创建用友U8 API应…

c# TaskScheduler

这里记录下 TaskScheduler 的简单用法。 使用场景: 使用 Task 的时候,大家知道用 TaskFactory.StartNew 可以用来创建一个 Task 。这里如果创建了 3 个,那么这3个 Task 就各自放飞直接运行了。 class Program {private static TaskFactory…

Go语言错误分类

错误的分类 在 Go 语言中,错误是通过实现 error 接口的类型表示的,但不同场景下的错误可以按性质和用途进行分类。以下是 Go 语言错误的常见分类,以及每类错误的解释和示例: 标准错误类型 标准库中定义了许多常见的错误类型&…

Couchbase的OLAP支持情况

Couchbase 是一个高性能的 NoSQL 数据库,主要用于在线事务处理(OLTP)场景,但它也提供了一些功能来支持在线分析处理(OLAP)需求。以下是 Couchbase 对 OLAP 支持的几个方面: 1. N1QL 查询语言 …

检查读取数据寄存器输出的多扇出

为使第二寄存器被 RAM 原语吸收,来自存储器阵列的数据输出位的扇出必须为 1 。这在下图中进行了说明。 检查地址 / 读取数据寄存器上的复位信号 不应复位存储器阵列。只有 RAM 的输出可以容许复位。复位必须是同步的,以便将输出寄存器推断到 RAM 基元…

MeiliSearch:一款轻量级开源搜索引擎

Meilisearch 是由 Meili (一家总部位于法国的软件开发公司)创建的搜索引擎,目前在 Github 上有 47.9k stars。 Meillisearch 具备以下特色功能(ChatGPT-4o 翻译): 混合搜索:结合语义搜索和全文…

随手记——conda迁移虚拟环境后不能使用Linux命令解决方案

在Ubuntu使用conda pack打包环境迁移之后发现存在以下问题; conda迁移环境是为了更短的的在新机器上搭建一个环境;我记录一下遇见的问题; 步骤: 【默认安装了conda-pack库,我都是安装到base虚拟环境中,打…

MongoDB-ObjectID 生成器

前言 MongoDB中一个非常关键的概念就是 ObjectID,它是 MongoDB 中每个文档的默认唯一标识符。了解 ObjectID 的生成机制不仅有助于开发人员优化数据库性能,还能帮助更好地理解 MongoDB 的设计理念。 什么是 MongoDB ObjectID? 在 MongoDB …

发愿和许愿的区别是什么?

在许多宗教和文化中,发愿和许愿都是人们表达内心愿望、祈求神灵保佑的重要方式。尽管这两个词在日常生活中经常被交替使用,但它们在含义和实践上存在一些重要的区别。本文就来详细说说发愿和许愿的区别,并提供相关的背景信息和建议。 1. 定义…

渗透测试工具 -- SQLmap安装教程及使用

随着网络安全问题日益严峻,渗透测试成为了保护信息安全的重要手段。而在渗透测试的众多工具中,SQLmap凭借其强大的自动化SQL注入检测和利用能力,成为了网络安全专家必备的利器。那么,你知道如何高效地使用SQLmap进行漏洞扫描吗&am…

SpringBoot 整合 RabbitMQ 实现流量消峰

RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将 RocketMQ 捐献给了 Apache,当然了今天的主角还…

Git-分支(branch)常用命令

分支 我们在做项目开发的时候,无论是软件项目还是其他机械工程项目,我们为了提高效率以及合理的节省时间等等原因,现在都不再是线性进行,而是将一个项目抽离出诸进行线,每一条线在git中我们就叫做分支,bran…

goenv go 环境配置

Golang环境配置 1. goenv工具 goenv 是一个用于管理 Go 语言版本的工具,类似于 Python 的 pyenv 或 Ruby 的 rbenv。不过需要注意的是,goenv 并不是一个官方维护的工具,而是一个社区项目。Go 语言本身已经提供了很好的版本管理工具&#xf…

Electron electron-builder.yml 配置 (自定义包名,用户自定义安装目录...)

electron-builder.yml 配置 # 唯一的应用程序标识符,用于操作系统级别的识别 appId: com.electron.app# 应用程序的名称,显示在用户界面上 productName: 我的应用# 定义构建资源目录,放置图标、证书等资源文件 directories:buildResources: …