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

实现 el-table 中键盘方向键导航功能vue2+vue3(类似 Excel)

实现 el-table 中键盘方向键导航功能vue2+vue3(类似 Excel)

功能需求

在 Element UI 的 el-table 表格中实现以下功能:

  • 使用键盘上下左右键在可编辑的 el-input/el-select 之间移动焦点
  • 焦点移动时自动定位到对应单元格
  • 支持光标位置自动调整,提升编辑体验
完整解决方案(vue2)
1. 表格结构修改

在 el-table 中添加键盘事件监听,并为可编辑元素添加定位标识:

<template><el-table :data="tableData" border style="width: 100%" size="small"><el-table-column prop="account_id" label="结算账户" width="180" align="center"><template slot-scope="scope"><el-select v-model="scope.row.account_id" placeholder="请选择账户" clearable filterable @keydown.native.stop="onKeyDown(scope.$index, 'account_id', $event)" :ref="getInputRef(scope.$index, 'account_id')"><el-option label="a" value="1" /><el-option label="b" value="2" /></el-select></template></el-table-column><el-table-column prop="money" label="结算金额" width="180" align="center"><template slot-scope="scope"><el-input v-model="scope.row.money" clearable @keydown.native.stop="onKeyDown(scope.$index, 'money', $event)" :ref="getInputRef(scope.$index, 'money')"/></template></el-table-column><el-table-column prop="remark" label="备注" align="center"><template slot-scope="scope"><el-input v-model="scope.row.remark" @keydown.native.stop="onKeyDown(scope.$index, 'remark', $event)" :ref="getInputRef(scope.$index, 'remark')"></el-input></template></el-table-column></el-table>
</template>
2. 核心 JavaScript 逻辑

在 Vue 组件的 methods 中添加焦点导航控制方法:

<script>
export default {data() {return {tableData: [{},{},{},{}],columns: [{prop: 'account_id'},{prop: 'money'},{prop: 'remark'}],refList: {}}},methods: {getInputRef(rowIndex, columnProp) {return `input-${rowIndex}-${columnProp}`},onKeyDown(rowIndex, columnProp, event) {// 当前列在columns数组中的索引const columnIndex = this.columns.findIndex((c) => c.prop === columnProp)// 计算下一个输入框的位置,如果是当前行的最后一个输入框则移到下一行的第一个输入框let nextColumnIndex = (columnIndex + 1) % this.columns.length;let nextRowIndex;switch(event.keyCode) {case 38:nextRowIndex = rowIndex - 1;nextColumnIndex = columnIndex;break;case 40:nextRowIndex = rowIndex + 1;nextColumnIndex = columnIndex;break;case 37:nextRowIndex = columnIndex === 0 ? rowIndex - 1 : rowIndexnextColumnIndex = columnIndex === 0 ? this.columns.length - 1 : columnIndex - 1break;case 39:nextRowIndex = columnIndex === this.columns.length - 1 ? rowIndex + 1 : rowIndexbreak;}const nextInputRef = `input-${nextRowIndex}-${this.columns[nextColumnIndex].prop}`const currentInputRef = `input-${rowIndex}-${this.columns[columnIndex].prop}`this.$nextTick(() => {if (this.$refs[nextInputRef]) {this.$refs[nextInputRef].focus()if (this.$refs[currentInputRef]) {this.$refs[currentInputRef].blur()}}})}}
}
</script>
完整解决方案(vue3)
 <template><el-table :data="tableData" border style="width: 100%" size="small"><el-table-column prop="account_id" label="结算账户" width="180" align="center"><template #default="{ row, $index,column }"><el-select v-model="row.account_id" placeholder="请选择账户" clearable filterable @keydown="onKeyDown($index,column.property,$event)" :ref="(el)=>setRef(el,`input-${$index}-${column.property}`)"><el-option label="a" value="1" /><el-option label="b" value="2" /></el-select></template></el-table-column><el-table-column prop="money" label="结算金额" width="180" align="center"><template #default="{ row, $index,column }"><el-input v-model="row.money" clearable @keydown="onKeyDown($index,column.property,$event)" :ref="(el)=>setRef(el,`input-${$index}-${column.property}`)"/></template></el-table-column><el-table-column prop="remark" label="备注" align="center"><template #default="{ row,$index,column }"><el-input v-model="row.remark" @keydown="onKeyDown($index,column.property,$event)" :ref="(el)=>setRef(el,`input-${$index}-${column.property}`)"></el-input></template></el-table-column></el-table>
</template>
<script setup>
import { nextTick, ref } from 'vue'const tableData = [{},{},{},{}
]const columns = [{prop:'account_id'},{prop:'money'},{prop:'remark'}
]
const refList = ref({})
const setRef = (el,key)=>{refList.value[key] = el
}
function onKeyDown(rowIndex,columnProp,event){// 当前列在columns数组中的索引const columnIndex = columns.findIndex((c) => c.prop === columnProp)// 计算下一个输入框的位置,如果是当前行的最后一个输入框则移到下一行的第一个输入框let nextColumnIndex = (columnIndex + 1) % columns.length;let nextRowIndex;switch(event.keyCode){case 38:nextRowIndex = rowIndex - 1 ;nextColumnIndex = columnIndex;break;case 40:nextRowIndex = rowIndex + 1 ;nextColumnIndex = columnIndex;break;case 37:nextRowIndex = columnIndex === 0 ? rowIndex - 1 : rowIndexnextColumnIndex = columnIndex === 0 ? columns.length - 1 : columnIndex - 1break;case 39:nextRowIndex = columnIndex === columns.length - 1 ? rowIndex + 1 : rowIndexbreak;}const nextInputRef = `input-${nextRowIndex}-${columns[nextColumnIndex].prop}`const currentInputRef = `input-${rowIndex}-${columns[columnIndex].prop}`nextTick(() => {if (refList.value[nextInputRef]) {refList.value[nextInputRef].focus()refList.value[currentInputRef].blur()}})}
</script>

相关文章:

  • 从0开始学习R语言--Day30--函数型分析
  • Centos 7离线部署Nginx 高效省时
  • uniapp安卓GPIO电平控制
  • Milvus【部署 03】Linux OpenEuler 环境在线+离线安装及卸载
  • 【软考高级系统架构论文】论企业集成架构设计及应用
  • Milvus【工具 01】milvus_cli和可视化工具attu安装使用
  • uniapp vue2多选模糊下拉组件
  • 住宅老年护理软件:市场洞察与发展前景
  • 顶级思维方式——认知篇十一《传习录》笔记
  • leetcode:78. 子集
  • 手机摄影后期进阶:LR调色参数黄金比例表
  • LeetCode中K个链表的链接的解法
  • 从本地到云端:通过ToolJet和cpolar构建远程开发环境实践过程
  • 操作系统 第九章 部分
  • 详解HarmonyOS NEXT仓颉开发语言中的全局弹窗
  • 2024计算机保研--哈工大、中山、国防科大(二)
  • 前端高频面试题汇总
  • 【入门级-基础知识与编程环境:3、计算机网络与Internet的基本概念】
  • Flask框架index.html里引用的本地的js和css或者图片
  • RK3576 Yolo 部署
  • 英文外贸网站建设网站设计方案/关键字挖掘
  • 网站图标在哪里做修改/网站建设优化公司
  • 哪个网站可以做教师招聘题目/搜索引擎调词工具哪个好
  • 工程建设安全管理/百度关键词优化服务
  • 个人网站建立 学生/广东seo推广哪里好
  • 专业做营销网站/seo 推广