键盘方向键移动当前选中的table单元格,并可以输入内容

有类似于这样的表格,用的<table>标签。原本要在单元格的文本框里面输入内容,需要用鼠标一个一个去点以获取焦点,现在需要不用鼠标选中,直接用键盘的上下左右来移动当前正在输入的单元格文本框。

 const currentCell = React.useRef<HTMLElement | null>() // 储存当前选中的单元格const  handleArrowKeys = (event) => { // 当按下键盘方向键做的事情if (!currentCell || !currentCell.current) return;const cellIndex = currentCell?.current?.cellIndex;let newCell;switch (event.key) {case 'ArrowUp':newCell = currentCell.current?.parentElement?.previousElementSibling?.cells[cellIndex];break;case 'ArrowDown':newCell = currentCell.current?.parentElement?.nextElementSibling?.cells[cellIndex];break;case 'ArrowLeft':newCell = currentCell?.current?.previousElementSibling;break;case 'ArrowRight':newCell = currentCell?.current?.nextElementSibling;break;default:break;}if (newCell) {if(currentCell?.current){currentCell.current.style.border = 'solid 2px black'// currentCell.current.style.boxShadow = 'none'}currentCell.current = newCellnewCell.style.border = '3px solid #1890ff'// newCell.style.borderColor = '#1890ff'// newCell.style.boxShadow = '0 0 10px 5px #1890ff'}}useEffect(()=>{// 鼠标点击事件,因为第一次选中单元格肯定是要点击document.addEventListener("click", (e: MouseEvent) => {const target = e.target as HTMLElement// console.log(target.tagName, 'target')// 这里要判断被点击的对象是不是你需要监听的表格的单元格const isActive = (target.tagName === 'TD' || target.tagName === 'TH') && ...if (isActive) {if(currentCell?.current){ // 将原本被选中的单元格样式改为正常样式currentCell.current.style.border = 'solid 2px black'}// 新的单元格存起来,并高亮显示currentCell.current = targettarget.style.border = '3px solid #1890ff'} else {// 如果被点击的不是需要监听的地方,则整个表格“失去焦点”if(currentCell?.current){currentCell.current.style.border = 'solid 2px black'currentCell.current = null}}})document.addEventListener('keydown', function(e) {// console.log(e, 'e')if (e.ctrlKey || e.altKey){// 这是按ctrl+  alt+的情况,很多快捷键方式不知道怎么模仿。} else if (e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {handleArrowKeys(e);} else if (e.key === 'Insert' ||  // 按下的是插入键e.key === 'Home' ||  // 按下的是Home键e.key === 'End'  // 按下的是End键// 其他需要处理的按键) {return} else{if(!currentCell || !currentCell.current) returnlet childNodes = currentCell.current.childNodeslet inputIndex: any = null, textAreaIndex: any = nullchildNodes.forEach((node, index) => {if(node.tagName === 'INPUT') inputIndex = indexif(node.tagName === 'TEXTAREA') textAreaIndex = index})if(inputIndex !== null){if (e.key === 'Backspace' ||  // 按下的是退格键e.key === 'Delete'// 其他需要处理的按键) {childNodes[inputIndex].value = ''} else if(e.key.length === 1) {childNodes[inputIndex].value = childNodes[inputIndex].value + e.key}}else if(textAreaIndex !== null){if (e.key === 'Backspace' ||  // 按下的是退格键e.key === 'Delete'// 其他需要处理的按键) {childNodes[textAreaIndex].value = ''} else if(e.key.length === 1) {childNodes[textAreaIndex].value = childNodes[inputIndex].value + e.key}}}});},[])

这种方式,实现的功能就是点击单元格,注意不能点击到格里的文本框(因为我觉得文本框都是单击它就获取了焦点,键盘方向键也是用来控制光标位置的,这里没有过多的去纠结去探究,也许可以做到),然后键盘的上下左右就能控制当前选中的单元格,输入,就能改变单元格的文本框的值。其实这样我觉得就和excel单击单元格选中,输入就是覆盖整个内容,方向键控制选中单元格;双击单元格才是继续编辑单元格内容,方向键控制光标差不多,不过我这个变成了单击单元格是选中,然后输入覆盖,单击文本框是继续输入。

但是,这样是有弊端的,代码中也能看出来,对于ctrl+,alt+这些快捷键的功能我没有模仿出来,可能跟个人能力有关,而且就算有办法我觉得可能也太复杂了(不想折腾),还有就是很重要的一点,他没办法输入中文,因为我是监听键盘按下的事件,然后获得它的key,那用户想输入中文,我也只能获取到一个一个的英文字母(本人也想过偷懒,因为这个系统这里的表格大多数是不用输入中文,少数有中文,后面闲着没事,就问了chat gpt得到一些灵感)。

 const currentCell = React.useRef<HTMLElement | null>() // 储存当前选中的单元格const  handleArrowKeys = (event) => { // 当按下键盘方向键做的事情if (!currentCell || !currentCell.current) return;const cellIndex = currentCell?.current?.cellIndex;let newCell;switch (event.key) {case 'ArrowUp':newCell = currentCell.current?.parentElement?.previousElementSibling?.cells[cellIndex];break;case 'ArrowDown':newCell = currentCell.current?.parentElement?.nextElementSibling?.cells[cellIndex];break;case 'ArrowLeft':newCell = currentCell?.current?.previousElementSibling;break;case 'ArrowRight':newCell = currentCell?.current?.nextElementSibling;break;default:break;}if (newCell) {if(currentCell?.current){currentCell.current.style.border = 'solid 2px black'let input = document.getElementById("dynamicInput");if (input) {input.remove();}}currentCell.current = newCellnewCell.style.border = '3px solid #1890ff'let input = document.createElement("input");input.type = "text";input.style.position = "absolute";input.style.left = "-9999px";input.id = "dynamicInput";newCell.appendChild(input);input.addEventListener("input", handleInput);input.focus();}}const handleInput = (e) => {if(!currentCell || !currentCell.current) returnlet childNodes = currentCell.current.childNodeslet inputIndex: any = null, textAreaIndex: any = nullchildNodes.forEach((node, index) => {console.log(node, 'node')if(node.tagName === 'INPUT' && !node.id) inputIndex = indexif(node.tagName === 'TEXTAREA') textAreaIndex = index})console.log(e, 'e')if(inputIndex !== null){childNodes[inputIndex].value = e.target.value}else if(textAreaIndex !== null){childNodes[textAreaIndex].value = e.target.value}}useEffect(()=>{// 鼠标点击事件,因为第一次选中单元格肯定是要点击document.addEventListener("click", (e: MouseEvent) => {const target = e.target as HTMLElement// console.log(target.tagName, 'target')// 这里要判断被点击的对象是不是你需要监听的表格的单元格const isActive = (target.tagName === 'TD' || target.tagName === 'TH') && ...if (isActive) {if(currentCell?.current){ // 将原本被选中的单元格样式改为正常样式currentCell.current.style.border = 'solid 2px black'let input = document.getElementById("dynamicInput");if (input) {input.remove();}}// 新的单元格存起来,并高亮显示currentCell.current = targettarget.style.border = '3px solid #1890ff'let input = document.createElement("input");input.type = "text";input.id = "dynamicInput";input.style.position = "absolute";input.style.left = "-9999px";target.appendChild(input);input.addEventListener("input", handleInput);input.focus();} else {// 如果被点击的不是需要监听的地方,则整个表格“失去焦点”if(currentCell?.current){currentCell.current.style.border = 'solid 2px black'currentCell.current = nulllet input = document.getElementById("dynamicInput");if (input) {input.remove();}}}})document.addEventListener('keydown', function(e) {// console.log(e, 'e')if (e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {handleArrowKeys(e);}});},[])

后面这种方法就改成了给当前选中的单元格插入一个用户看不到的自动获取焦点的input,然后监听这个文本框的input事件,并实时将这个文本框的内容更新到对应的文本框。才刚实现这个,没有经过大量操作的测试,不知道会不会有什么bug,目前没有什么大问题。

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

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

相关文章

【数据结构初阶】单链表SLlist

描述 不同于顺序表&#xff0c;顺序表的数据是存储在一个连续的空间里的 而链表它是链接起来的结构体地址。 所以我们不用像顺序表一样先创建一块空间出来&#xff0c;而是创建一个能存数据节点和节点与下一个节点之间的连接&#xff1b; 所以&#xff1a;“一个能存数据节点…

词向量笔记

一、词向量的世界排名比赛MTEB MTEB: Massive Text Embedding Benchmark 二、词向量的维数 词向量的维数d1一般取20~500之间

百分点科技|怎样做数据运营,才能让数据中台真正用起来?

导读&#xff1a;大多数企业用户已完成数据平台初步建设工作&#xff0c;但数据在业务运营和管理中没有发挥应有价值。数据开发工作繁重&#xff0c;数据质量问题严重&#xff0c;IT、数据和业务协作不畅&#xff0c;诸多问题依然困扰着企业用户的IT部门和数据部门。数据运营成…

起立科技(起鸿)在第25届高交会上展示透明OLED技术创新

第二十五届中国国际高新技术成果交易会 日期&#xff1a;2023年11月15日 地点&#xff1a;福田会展中心7号馆 深圳&#xff0c;2023年11月15日 — 起鸿科技&#xff0c;作为透明OLED领域的引领者&#xff0c;于今日参展了第二十五届中国国际高新技术成果交易会。这一展会将汇…

『亚马逊云科技产品测评』活动征文|通过lightsail一键搭建Drupal VS 手动部署

『亚马逊云科技产品测评』活动征文&#xff5c;通过lightsail一键搭建Drupal 提示&#xff1a;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚…

微服务架构中的 熔断和降级

文章目录 熔断判定服务的健康状态服务恢复正常 降级跨服务降级自身服务提供有损服务具体案例分析 熔断 微服务架构中&#xff0c;如果需要保障可用性&#xff0c;其中一个方式就是 熔断。熔断在微服务架构里面是指 当微服务本身出现问题的时候&#xff0c;它会拒绝新的请求&am…

大学生如何免费认证,下载,安装MATLAB

下载 打开学校图书馆官网 选择版本后&#xff0c;点击下载 注册绑定个人认证 前提&#xff01;需要有学校邮箱【以edu.cn结尾的】 进入mathworks官网 注册账户 安装 下载完后&#xff0c;打开 选择&#xff1a;setup 安装程序 勾选&#xff1a;是&#xff1b;选择&#xf…

机器学习第10天:集成学习

文章目录 机器学习专栏 介绍 投票分类器 介绍 代码 核心代码 示例代码 软投票与硬投票 bagging与pasting 介绍 核心代码 随机森林 介绍 代码 结语 机器学习专栏 机器学习_Nowl的博客-CSDN博客 介绍 集成学习的思想是很直观的&#xff1a;多个人判断的结合往往比…

身份证阅读器和社保卡读卡器Harmony鸿蒙系统ArkTS语言SDK开发包

项目需求&#xff0c;用ArkTS新一代开发语言实现了在Harmony鸿蒙系统上面兼容身份证阅读器和社保卡读卡器&#xff0c;调用了DonseeDeviceLib.har这个读卡库。 需要注意的是&#xff0c;鸿蒙系统的app扩展名为.hap&#xff0c;本项目编译输出的应用为&#xff1a;entry-default…

下厨房网站月度最佳栏目菜谱数据获取及分析PLus

目录 概要 源数据获取 写Python代码爬取数据 Scala介绍与数据处理 1.Sacla介绍 2.Scala数据处理流程 数据可视化 最终大屏效果 小结 概要 本文的主题是获取下厨房网站月度最佳栏目近十年数据&#xff0c;最终进行数据清洗、处理后生成所需的数据库表&#xff0c;最终进…

JPA整合Sqlite解决Dialect报错问题, 最新版Hibernate6

前言 我个人项目中&#xff0c;不想使用太重的数据库&#xff0c;而内嵌数据库中SQLite又是最受欢迎的&#xff0c; 因此决定采用这个数据库。 可是JPA并不支持Sqlite&#xff0c;这篇文章就是记录如何解决这个问题的。 原因 JPA屏蔽了底层的各个数据库差异&#xff0c; 但是…

竞赛 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

亚马逊第二个大语言模型 Olympus 即将上线

据外媒爆料&#xff0c;亚马逊正在训练他的第二个大语言模型——Olympus&#xff0c;很有可能在今年12月份上线。亚马逊计划将Olympus接入在线零售商店、Echo等设备上的Alexa语音助手&#xff0c;并为AWS平台提供新的功能。据说这个大语言模型规模达到2万亿&#xff08;2000B&a…

读《Segment Anything in Defect Detection》

摘要 (好像只是说把SAM应用到了红外缺陷分割领域) 引言 无损检测得到红外图像&#xff0c;根据热能观察异常 贡献&#xff1a; •从两个光学脉冲热成像系统构建广泛的缺陷热数据库&#xff0c;包括各种材料并释放它们。 • 开发DefectSAM&#xff0c;这是第一个用于缺陷检测…

MAC地址注册的网络安全影响和措施分析

MAC地址注册对网络安全具有重要影响&#xff0c;同时也需要采取相应的措施来应对潜在的安全风险。以下是有关MAC地址注册的网络安全影响和应对措施的分析&#xff1a; 影响&#xff1a; 1. 身份验证&#xff1a;MAC地址注册可用于设备的身份验证&#xff0c;但MAC地址本身并不…

不标年份的葡萄酒质量好吗?

我们在葡萄酒标上经常看到生产年份&#xff0c;也就是指全部葡萄采摘的年份。旧世界葡萄酒产国认为葡萄酒年份对他们的影响较大&#xff0c;而新世界葡萄酒&#xff0c;年份的意义就稍微小些。甚至有一部分葡萄酒酒标上没有年份。在酒标上没有标注年份的葡萄酒&#xff0c;被称…

学习无人机代码框架【第一天】---VMware 安装Ubuntu16.04时显示不全的解决方法

ros环境配置篇 环境配置在vmware上安装ubantu16.04操作系统安装完成后显示界面太小解决办法其他遇到的一些ubantu问题最后一步是在ubantu16上安装ros-kinetic其他很重要的一个工具是安装vmware-tool&#xff0c;可以支持把外部的文件或文字传入到虚拟机中管理不同的终端的软件代…

[C/C++] 数据结构 LeetCode:用队列实现栈

题目描述: 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。int pop() 移除并返回栈顶元…

kubernetes集群编排——etcd

备份 从镜像中拷贝etcdctl二进制命令 [rootk8s1 ~]# docker run -it --rm reg.westos.org/k8s/etcd:3.5.6-0 sh 输入ctrlpq快捷键&#xff0c;把容器打入后台 获取容器id [rootk8s1 ~]# docker ps 从容器拷贝命令到本机 docker container cp c7e28b381f07:/usr/local/bin/etcdc…

最大子段和(分治法+动态规划法)

求最大子段和 此类问题通常是求数列中连续子段和的最大值&#xff0c;经典的股票问题就是考察的这个思想及拓展。 例题&#xff1a; AcWing:1054. 股票买卖 Leetcode:53. 最大子数组和 分治法O(nlogn) 此类问题时分适合采用分治思想&#xff0c;因为所有子区间 [ s t a r t …