当前位置: 首页 > news >正文

键盘方向键移动当前选中的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.lryc.cn/news/236512.html

相关文章:

  • (八)、基于 LangChain 实现大模型应用程序开发 | 基于知识库的个性化问答 (检索 Retrieval)
  • 高效案例检索工具,Alpha案例库智慧检索成为律师检索工具首选
  • stable diffusion十七种controlnet详细使用方法总结
  • 【机器学习基础】对数几率回归(logistic回归)
  • 团结引擎已全面支持 OpenHarmony 操作系统
  • 【brpc学习案例实践一】rpc服务构造基本流程
  • Redis数据的持久化
  • uniapp App 端 版本更新检测
  • python用最小二乘法实现平面拟合
  • SpringCloud微服务:Nacos和Eureka的区别
  • 基于Springboot+Vue的校园在线打印预约系统
  • 计算机毕业设计选题推荐-掌心办公微信小程序/安卓APP-项目实战
  • 1.1二分查找
  • 提升工作效率,打造精细思维——OmniOutliner 5 Pro for Mac
  • idea显示pom.xml文件漂黄警告 Dependency maven:xxx:xxx is vulnerable
  • Linux中安装部署环境(JAVA)
  • Zabbix Proxy分布式监控
  • 前端设计模式之【代理模式】
  • Canal+Kafka实现MySQL与Redis数据同步(二)
  • NOIP2023模拟19联测40 诡异键盘
  • 算法设计与分析 | 众数问题(c语言)
  • sql server外键设置
  • R语言实现多变量孟德尔随机化分析(1)
  • 搭建 AI 图像生成器 (SAAS) php laravel
  • Maven引用本地jar包
  • 一起学docker系列之五docker的常用命令--操作容器的命令
  • WPF打开对话框选择文件、选择文件夹
  • nginx学习(3)
  • 【系统架构设计】计算机公共基础知识: 4 数据库系统
  • 主键问题以及分布式 id