首页 > 其他分享 >VUE2-表格根据方向键聚焦编辑框

VUE2-表格根据方向键聚焦编辑框

时间:2025-01-15 10:30:50浏览次数:3  
标签:case direction 方向键 const target break VUE2 input 编辑框

需求

项目需要表格内的编辑框可以根据上下左右方向键去自动聚焦

实现思路

查阅网上的资料,是给表格内的每一个编辑框增加一个标识,要么类,要么是类似递增的一个id,然后监听键盘事件,但是我觉得这样不好,需要手动给每个编辑框加标识,太麻烦了。

我的思路是写一个指令"keyboard-navigation",仅需给需要的表格绑定该指令即可(多个表格也可以),极大的减少手部运动,果然懒是第一生产力。

<el-table :data="tableData" v-keyboard-navigation>
</el-table>

 指令大概实现思路是,获取当前表格中的聚焦元素,如果是左右键则向上递归找到td,然后再定位该td,获取相邻td后向下递归找到编辑框进行focus聚焦,上下键思路也差不多,需要找到该td的相邻行,我这里的代码如果碰到禁用的编辑框会跳过。

在directive.js文件中添加下方代码

Vue.directive("keyboard-navigation", {
  bind(el) {
    const handleKeydown = (event) => {
      const activeElement = document.activeElement;

      // 检查当前聚焦的元素是否为 input
      if (activeElement && activeElement.tagName.toLowerCase() === "input") {
        // 检查 input 是否在表格内
        let parent = activeElement.parentElement;
        let isInTable = false;
        while (parent) {
          if (parent.tagName.toLowerCase() === "table") {
            isInTable = true;
            break;
          }
          parent = parent.parentElement;
        }

        if (isInTable) {
          // 处理方向键
          switch (event.key) {
            case "ArrowUp":
            case "Up":
              event.preventDefault();
              navigateInput(activeElement, "up");
              break;
            case "ArrowDown":
            case "Down":
              event.preventDefault();
              navigateInput(activeElement, "down");
              break;
            case "ArrowLeft":
            case "Left":
              event.preventDefault();
              navigateInput(activeElement, "left");
              break;
            case "ArrowRight":
            case "Right":
              event.preventDefault();
              navigateInput(activeElement, "right");
              break;
            default:
              break;
          }
        }
      }
    };

    // 绑定事件
    el.addEventListener("keydown", handleKeydown);

    // 清理事件监听
    el._removeKeyboardListener = () => {
      el.removeEventListener("keydown", handleKeydown);
    };
  },
  unbind(el) {
    // 解绑事件
    if (el._removeKeyboardListener) {
      el._removeKeyboardListener();
    }
  },
});
// 导航函数,根据方向查找相邻的输入字段并聚焦
function navigateInput(currentInput, direction) {
  const td = currentInput.closest("td");
  if (!td) return;

  const tr = td.parentElement;
  if (!tr) return;

  const table = tr.closest("table");
  if (!table) return;

  const rows = Array.from(table.rows);
  const rowIndex = rows.indexOf(tr);
  const cellIndex = Array.from(tr.cells).indexOf(td);

  let targetRow, targetCell;

  switch (direction) {
    case "up":
      if (rowIndex > 0) targetRow = rows[rowIndex - 1];
      break;
    case "down":
      if (rowIndex < rows.length - 1) targetRow = rows[rowIndex + 1];
      break;
    case "left":
      targetCell = tr.cells[cellIndex - 1];
      break;
    case "right":
      targetCell = tr.cells[cellIndex + 1];
      break;
    default:
      break;
  }

  if (targetRow) {
    // 递归查找可聚焦的 input
    const targetInput = findFocusableInput(targetRow, cellIndex, direction);
    if (targetInput) {
      targetInput.focus();
    }
  } else if (targetCell) {
    // 在当前行查找可聚焦的 input
    const targetInput = findFocusableInput(targetCell, null, direction);
    if (targetInput) {
      targetInput.focus();
    }
  }
}
// 递归查找可聚焦的输入框
function findFocusableInput(target, cellIndex, direction) {
  let input = null;

  if (target instanceof HTMLTableCellElement) {
    // 在当前单元格查找 input
    input = target.querySelector("input:not([disabled])");
    if (!input) {
      // 若当前单元格没有可聚焦的 input,继续向左或向右查找
      const siblingCells = Array.from(target.parentElement.cells);
      const nextCellIndex =
        siblingCells.indexOf(target) +
        (direction === "left" ? -1 : direction === "right" ? 1 : 0);
      if (nextCellIndex >= 0 && nextCellIndex < siblingCells.length) {
        input = findFocusableInput(
          siblingCells[nextCellIndex],
          null,
          direction
        );
      }
    }
  } else if (target instanceof HTMLTableRowElement) {
    // 在行中查找指定列的单元格
    if (cellIndex >= 0 && cellIndex < target.cells.length) {
      const targetCell = target.cells[cellIndex];
      if (targetCell) {
        input = targetCell.querySelector("input:not([disabled])");
        if (!input) {
          // 若当前单元格没有可聚焦的 input,继续查找上一行或下一行
          if (direction === "up" && target.previousElementSibling) {
            input = findFocusableInput(
              target.previousElementSibling,
              cellIndex,
              direction
            );
          } else if (direction === "down" && target.nextElementSibling) {
            input = findFocusableInput(
              target.nextElementSibling,
              cellIndex,
              direction
            );
          }
        }
      }
    }
  }

  return input;
}

注意

如果指令绑定是在el-table上的话,需要注意如果有用到固定列fixed功能,固定区域与非固定区域是分开的不同表格,这个跟el-table组件本身的实现逻辑有关,这会导致固定区域跳不到非固定区域!

标签:case,direction,方向键,const,target,break,VUE2,input,编辑框
From: https://blog.csdn.net/weixin_47416493/article/details/145152908

相关文章

  • 基于SpringBoot框架+Vue2.x+Element-UI技术的在线博客系统设计与实现
         博主介绍:硕士研究生,专注于信息化技术领域开发与管理,会使用java、标准c/c++等开发语言,以及毕业项目实战✌    从事基于javaBS架构、CS架构、c/c++编程工作近16年,拥有近12年的管理工作经验,拥有较丰富的技术架构思想、较扎实的技术功底和资深的项目管理经验......
  • Vue2-父子组件通信
    子组件<template><div><el-form><el-form-itemlabel="码值"><el-inputv-model="code"@input="sendFather"></el-input></el-form-item><el-form-itemlabe......
  • Windows10下安装vue2.0项目所需环境
    一、Node.js版本管理器NVM安装1.下载NVM安装包        nvm全英文也叫node.jsversionmanagement,是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具,为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js。目前最新版本v1.1.12......
  • Vue2+OpenLayers调用WMTS服务初始化天地图示例
    目录一、案例截图二、安装OpenLayers库三、WMTS服务详解四、完整代码五、Gitee源码一、案例截图二、安装OpenLayers库npminstallol三、WMTS服务详解WMTS(WebMapTileService)是一种标准的网络地图服务协议,用于提供基于瓦片的地图数据。它允许客户端请求地图的具......
  • Vue3 hook 函数模块化 类似vue2 mixin
    1、优点代码功能模块化,复用代码2、建立新建hooks文件夹,在src下src/hooks/use功能.js3、案例a、模块化src/hooks/usepoint.jsimport{reactive,onMounted,onBeforeUnmount}from'vue';exportdefaultfunction(){letponint=reactive({x:0,......
  • vue2.0+vue3.0一学就会全套教程【组件注册与组件通信】
    今天出门,物业小姐姐打招呼说今天是腊八节,叫吃一碗腊八粥。今天是腊八节呀,记得小时候每到这个时候已是浓浓的年味了了,如今粥入游子愁肠,便化作无数相思泪,香飘十里,犹未解远乡情。哈喽,大家好,我是鑫阳,今天一起看看Vue组件开发吧!1、为什么使用组件组件(Component)是Vue.js最核心......
  • Vue2-内联脚本
    vue2与vue3的差异响应式系统的差异:Vue2使用Object.defineProperty实现响应式系统,而Vue3使用了Proxy。在Vue2中,对于数组的响应式处理有一些限制,比如不能检测数组索引和长度的变化,而Vue3中这些问题得到了解决。组件和API的变化:Vue2中的组件选项(如data,m......
  • vue2 基本使用
    1.模板2.computed和watch3.class和style4.条件5.循环6.事件7.表单 一、模板插值、表达式<template><div>p>文本插值{{message}}</p><p>js表达式{{flag:'yes':'no'}}(只能是表达式,不能是js语句)</p></di......
  • 本地如何访问vue2 生成的dist代码
    前言当你使用VueCLI或其他构建工具构建Vue2项目时,它会生成一个dist文件夹,这个文件夹包含了你项目的生产环境版本的静态资源文件(HTML、JavaScript和CSS)。直接打开dist文件夹中的index.html文件在某些情况下是可以的,但是由于浏览器的安全限制,特别是当你的应用需要从......
  • vue2项目升级为vue3,有哪些需要修改的?
    将Vue2项目升级为Vue3时,前端开发者需要关注多个方面的修改。以下是需要修改的关键点,按照一定结构进行归纳:1.全局和内部API的迁移全局API的更改:在Vue3中,许多全局API已经发生了改变。例如,Vue.use()被替换为app.use(),Vue.prototype被替换为app.config.globalProperties,而......