news 2026/5/6 15:32:46

react实现虚拟键盘支持Ant design Input和普通input Dom元素-升级篇

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
react实现虚拟键盘支持Ant design Input和普通input Dom元素-升级篇

本文基于上一篇文章进行优化,不需要关注业务input怎么封装,不涉及业务改动。通用自定义数组键盘输入功能如下:直接贴代码

import type { FC } from 'react'; import React, { useEffect } from 'react'; import { useRecoilValue } from 'recoil'; import { EPanelKeyModeType, EPanelNumCommand } from '@/pages/editor1/common/enum'; import ConfigManage from '@/pages/global/ConfigManage'; import { panelCommandStore } from '@/stores'; import { updateKeyMode } from '@/utils/panel'; export type AnyObjectImple = Record<string, string | number>; const INPUTTAGNAME = 'INPUT'; const INPUTTEXT = 'text'; const INPUTTEL = 'tel'; /** * 通用业务数字键盘计算 * @type cueMode: 文本模式, cueMode: 数字模式两种 * @waring 计算文本之前需要将文本现有数据 set 到panelNumberStore的originalVal上 * @desc 考虑到这里业务的逻辑较复杂,将业务提取为公用业务组件 * @desc 任何地方都可以使用该组件进行数字键盘的计算、文本的计算 * @desc 追加文本框光标位置的计算 * @returns */ const NumberKeyboard: FC = () => { // 指令 const panelCommand = useRecoilValue(panelCommandStore); const IsNormalScreen = ConfigManage.getExpandCfg().IsNormalScreen; useEffect(() => { // 文字输入框添加onfocus, onblur监听,调起小控台数字按键 if (IsNormalScreen) return; const isNeedBlur = (relateDM) => { if (relateDM?.tagName !== INPUTTAGNAME) { return true; } else { return relateDM?.type !== INPUTTEXT && relateDM?.type !== INPUTTEL; } }; const isTargetInput = (targetDMParam: HTMLInputElement) => { return ( targetDMParam?.tagName === INPUTTAGNAME && (targetDMParam?.type === INPUTTEXT || targetDMParam?.type === INPUTTEL) ); }; const onFocus = (e: FocusEvent) => { if (isTargetInput(e.target as HTMLInputElement)) { updateKeyMode(EPanelKeyModeType.numberKeyMode); } }; const onBlur = (e: FocusEvent) => { const relateDOM = e.relatedTarget as HTMLInputElement; if (isTargetInput(e.target as HTMLInputElement) && isNeedBlur(relateDOM)) { updateKeyMode(EPanelKeyModeType.restoreLastMode); } }; document.addEventListener('focusin', onFocus); document.addEventListener('focusout', onBlur); return () => { document.removeEventListener('focusin', onFocus); document.removeEventListener('focusout', onBlur); }; }, []); /** * 数字按键相关指令 * @desc 1. 处理普通输入框 * @desc 2. 处理纯数字按键模式 * @return input 结果 */ const changeNumberCommand = (commandData) => { // 指令 const { command } = commandData; try { // 获取选定对象 const selection = window.getSelection(); if (selection) { // 如果是文本节点则先获取光标对象 const range = selection?.getRangeAt(0); // 获取光标对象的范围界定对象,一般就是textNode对象 const textNode: any = range.startContainer; // 获取输入框input Dom元素, 使用的是And design Input,textNode是div,div里面且套input等子元素 const inputNode = textNode?.getElementsByTagName('input')[0]; // 光标开始 const selectionStart = inputNode.selectionStart; // 结束位置 const selectionEnd = inputNode.selectionEnd; console.info('selectionStart', selectionStart, 'selectionEnd', selectionEnd); // 处理指令运算: 数字 handleNumberCommand(command, inputNode); } } catch (e) {} }; /** * 数字指令处理 * @param command * @param inputNode */ const handleNumberCommand = (command, inputNode) => { // 业务指令转对应文本 let pressFpgaVal: number | string = command - EPanelNumCommand.num0; if (command === EPanelNumCommand.point) { pressFpgaVal = '.'; } /** * 1. 处理键盘指令,分数字模式和非数字模式,非数字模式直接追加内容,数字模式计算内容 * 2. 判断指令范围 * 3. 判断指令模式,处理对应模式数据 */ if (command >= EPanelNumCommand.num0 && command <= EPanelNumCommand.enter) { if (command <= EPanelNumCommand.point) { // 0-9数字处理指令 doNumberCommand(inputNode, pressFpgaVal); } else if (command === EPanelNumCommand.point) { // 小数点操作 // equalTen(); } else if ([EPanelNumCommand.add, EPanelNumCommand.minus].includes(command)) { // 运算指令暂时不支持 // opertBtn(command); } else if (command === EPanelNumCommand.back) { // 控台Back删除处理指令 doBackCommand(inputNode); } else if (command === EPanelNumCommand.enter) { // 控台Enter处理指令 doEnterCommand(inputNode); } } }; /** * 0-9数字处理指令 * @param command */ const doNumberCommand = (inputNode, pressFpgaVal) => { // 转换成字符串 const value = inputNode.value + ''; // 光标开始、结束位置 const selectionStart = inputNode.selectionStart; const selectionEnd = inputNode.selectionEnd; // 计算新值 const newValue = value.substr(0, selectionStart) + pressFpgaVal + value.substring(selectionEnd, value.length); console.info('value', value, newValue); // 事件发布到组件中input const evt = new UIEvent('inputchange', { bubbles: false, cancelable: false, }); const keyName = 'data'; evt[keyName] = { value: newValue, selectionStart: selectionStart + pressFpgaVal.toString().length, selectionEnd: selectionStart + pressFpgaVal.toString().length, }; // 触发onChange事件 inputNode.dispatchEvent(evt, newValue); }; /** * 控台Back删除处理指令 * @param command */ const doBackCommand = (inputNode) => { // 转换成字符串 const value = inputNode.value + ''; // 光标开始、结束位置 const selectionStart = inputNode.selectionStart; const selectionEnd = inputNode.selectionEnd; // 计算新值 const newValue = value.substr(0, selectionStart - 1) + value.substring(selectionEnd, value.length); console.info('value', value, newValue); // 事件发布到组件中input const evt = new UIEvent('inputchange', { bubbles: false, cancelable: false, }); const keyName = 'data'; evt[keyName] = { value: newValue, selectionStart: selectionStart - 1, selectionEnd: selectionStart - 1, }; // 触发onChange事件 inputNode.dispatchEvent(evt); }; /** * 控台Enter处理指令 * 触发失去焦点指令 * @param command */ const doEnterCommand = (inputNode) => { // 失焦事件发布到组件中input const evt = new UIEvent('enter', { bubbles: false, cancelable: false, }); // 触发onChange事件 inputNode.dispatchEvent(evt); }; /** * 初始化订阅数字键盘指令 */ useEffect(() => { if (panelCommand) { changeNumberCommand(panelCommand); } }, [panelCommand]); return <div />; }; export default NumberKeyboard;
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 5:55:55

播客批量下载终极指南:一键获取所有节目内容

还在为逐个下载播客节目而烦恼吗&#xff1f;Podcast Bulk Downloader 这款工具能够彻底解决你的痛点&#xff01;无论你是想离线收听喜爱的播客&#xff0c;还是需要批量获取音频内容进行研究&#xff0c;这个工具都能让你事半功倍。它支持图形界面和命令行两种操作方式&#…

作者头像 李华
网站建设 2026/4/23 15:43:22

小米运动自动刷步神器:2025年微信支付宝同步完美攻略

小米运动自动刷步神器&#xff1a;2025年微信支付宝同步完美攻略 【免费下载链接】mimotion 小米运动刷步数&#xff08;微信支付宝&#xff09;支持邮箱登录 项目地址: https://gitcode.com/gh_mirrors/mimo/mimotion 还在为微信运动排行榜上的名次发愁吗&#xff1f;想…

作者头像 李华
网站建设 2026/5/4 8:27:19

3个快速解决TranslucentTB任务栏透明工具启动失败的方法

3个快速解决TranslucentTB任务栏透明工具启动失败的方法 【免费下载链接】TranslucentTB 项目地址: https://gitcode.com/gh_mirrors/tra/TranslucentTB TranslucentTB是一款广受欢迎的任务栏透明工具&#xff0c;让Windows用户能够自定义美化桌面。然而在系统更新后&a…

作者头像 李华
网站建设 2026/5/1 8:30:30

深入解析ISRC编码及其在OGG文件中的应用

在音乐行业中,国际标准录音代码(ISRC)是一种独特的标识符,用于识别和管理音频录音。ISRC代码不仅有助于版权管理,还能帮助跟踪音乐在不同平台和市场中的使用情况。今天,我们将探讨ISRC代码的格式及其在OGG文件中的正确使用方式。 ISRC代码的格式 ISRC代码可以以两种形式…

作者头像 李华
网站建设 2026/5/2 19:39:36

你的测试又慢又不可靠-因为你测错了东西

GitHub 主页 关于Hyperlane框架 Hyperlane 是一个轻量级、高性能、跨平台的 Rust HTTP 服务器框架&#xff0c;构建于 Tokio 异步运行时之上。 核心特性 性能表现&#xff1a;Keep-Alive开启324,323 QPS&#xff0c;关闭51,031 QPS | 统一API&#xff1a;HTTP、WebSocket、…

作者头像 李华
网站建设 2026/5/5 19:23:34

机械革命 AX210 网卡断网断流、蓝牙断流问题解决办法

核心问题&#xff1a;​ Intel AX210 无线网卡出现的Wi-Fi频繁断线、网络波动&#xff08;断流&#xff09;以及蓝牙连接不稳定的问题。解决思路&#xff1a;​ 主要通过清理系统内冲突的隐藏虚拟网卡&#xff0c;并优化AX210网卡本身的电源管理设置来实现。具体操作步骤&#…

作者头像 李华