vxe表格分为vxe-table一般表格和vxe-grid高级表格,两者之间的区别我就不说啦,我们来实现这两种表格用键盘按动上下左右方向键达到移动聚焦的效果。话不多说,上正文!!!
首先在标签放入这两个事件:
<vxe-grid @cell-click="cellClickEvent" @keyup="keyDown($event)"></vxe-grid>
主要是利用vxe表格内置的@cell-click事件,来监听点击单元格的行号和列号,相当于坐标轴的x轴和y轴。然后再利用@keyup键盘监听函数来监听方向键。思路有了,来肝!!!
大家可以根据这DOM图来参考代码--------------------------------------------------------------------------------
let currCell = {} // 初始化当前选中的单元格行列号
let _currCell = {} // 拷贝初始化当前选中的单元格行列号
// 单元格点击事件
function cellClickEvent ({ row, column }) {
const currRow = Number(row._X_ROW_KEY.split('_')[1]) // 当前行号
const currCol = Number(column.id.split('_')[1]) // 当前列号
currCell = { 'row': currRow, 'column': currCol } // 当前行列号
}
// 方向键事件
function keyDown (e) {
if (!(e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40 || e.keyCode === 9)) return
// 如果不是上下左右方向键或Tab键直接返回(Tab键不放进来的话,会出现点击Tab键,聚焦到右边,但行列号还是原来位置)
_currCell = JSON.parse(JSON.stringify(currCell)) // 深拷贝初始值
const trs = document.querySelectorAll('.vxe-body--row') //所有的tr行
const cols = trs[0].querySelectorAll('td') // 所有的td列(每一行的列号都一致)
const maxTd = cols[cols.length - 1].getAttribute('colid').split('_')[1] // 最大列号
const minTd = cols[0].getAttribute('colid').split('_')[1] //最小列号
const maxTr = trs[trs.length - 1].getAttribute('rowid').split('_')[1] // 最大行号
const minTr = trs[0].getAttribute('rowid').split('_')[1] // 最小行号
// 方向左键 37
if (e.keyCode === 37) {
if (currCell.column <= minTd) return // 如果当前单元格行号小于或等于最小列号,则直接返回
for (let index = 0; index < 520; index++) { // 防止中间列出现缺失情况,行亦如此
currCell.column--
let targetCell = document.querySelector(`tr[rowid=row_${currCell.row}]`).querySelector(`.col_${currCell.column}`)
if (targetCell) {
if (targetCell.querySelector('input')) {
targetCell.querySelector('input').focus(); return
}
if (targetCell.querySelector('.vxe-cell--label')) { // 只有点击后才会有输入框的单元格
targetCell.querySelector('.vxe-cell--label').click(); return
}
}
}
}
// 方向右键 39
if (e.keyCode === 39 || e.keyCode === 9) { // tab键在表格上与右键效果基本相似,可等同
if (currCell.column >= maxTd) return
for (let index = 0; index < 521; index++) {
currCell.column++
let targetCell = document.querySelector(`tr[rowid=row_${currCell.row}]`).querySelector(`.col_${currCell.column}`)
if (targetCell) {
if (targetCell.querySelector('input')) {
targetCell.querySelector('input').focus(); return
}
if (targetCell.querySelector('.vxe-cell--label')) {
targetCell.querySelector('.vxe-cell--label').click(); return
}
}
}
}
// 方向上键 38
if (e.keyCode === 38) {
if (currCell.row <= minTr) return
for (let index = 0; index < 1314; index++) {
currCell.row--
let targetRow = document.querySelector(`tr[rowid=row_${currCell.row}]`)
if (targetRow) { // 如果当前行都不存在,再查列会直接报错
let targetCell = document.querySelector(`tr[rowid=row_${currCell.row}]`).querySelector(`.col_${currCell.column}`)
if (targetCell) {
if (targetCell.querySelector('input')) {
targetCell.querySelector('input').focus(); return
}
if (targetCell.querySelector('.vxe-cell--label')) {
targetCell.querySelector('.vxe-cell--label').click(); return
}
}
}
}
}
// 方向下键 40
if (e.keyCode === 40) {
if (currCell.row >= maxTr) return
for (let index = 0; index < 9999; index++) {
currCell.row++
let targetRow = document.querySelector(`tr[rowid=row_${currCell.row}]`)
if (targetRow) {
let targetCell = document.querySelector(`tr[rowid=row_${currCell.row}]`).querySelector(`.col_${currCell.column}`)
if (targetCell) {
if (targetCell.querySelector('input')) {
targetCell.querySelector('input').focus(); return
}
if (targetCell.querySelector('.vxe-cell--label')) {
targetCell.querySelector('.vxe-cell--label').click(); return
}
}
}
}
}
currCell = _currCell; return // 如果跳转的不是输入框,就赋回给初始值
}
export { cellClickEvent, keyDown }
四个 if 里面都有一些公共代码,本来想在for循环里面加方向键的判断,但一想想性能可能会不好,就算了。
for 循环的循环次数看自己表格中缺失(删除或隐藏)的行列多少了,一般设置10以内就够了(别告诉我你喜欢中间隐藏 1 千条 (°ˊДˋ°) )
关于点击后才会生成 input 框的单元格,大家可以看下这图:
如果大家发现明明跳转的是可生成 input 框的单元格,但就是没有跳转,那可能是这行渲染代码没有加上: editRender: { name: "input" }
温馨提示:我这个代码没有实现在最左边单元格向左移动,自动跳转到上一行最右边那个单元格的效果,因为我感觉这样太飘了(反正我是不会觉得我菜)