基于layui实现的可编辑、可回车进入下一行的表格

开篇

这篇文章来源于我为别人处理一个问题的代码的简化,因为是简化,效果并不能完全展现出来,代码有许多需要修改的地方。因时间因素,此处不做修改,如果哪天有需要的时候,再把这些代码拿来优化使用吧。

代码功能

  1. 渲染一个表格
  2. 双击单元格可编辑(结果列)
  3. 在结果列点击回车,进入下一行
  4. 当鼠标悬停在结果列时,可出现下拉框

代码实现

javascript 复制代码
<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="./layui/css/layui.css" />
    <link rel="stylesheet" href="./layui/formSelects.css" />
    <style>
      #projectSelect {
        margin: 20px;
      }
      .dropdown-select {
        position: absolute;
        z-index: 1000;
        background-color: #fff;
        border: 1px solid #ddd;
        padding: 5px;
      }
    </style>
  </head>
  <body>
    <table
      id="projectSelect"
      class="layui-hide"
      lay-filter="projectFilter"
    ></table>

    <script src="./layui/layui.js"></script>
    <script src="./layui/jquery-3.7.1.min.js"></script>
    <script>
      // 是否点击了单元格
      var isEnter = false;
      // 全局变量,存储当前编辑的行索引
      let currentEditingRowIndex = -1;
      layui.use(["table"], function () {
        var table = layui.table;

        // 示例数据
        var selectedProjects = [
          { 序号: 1, 代码: "1001", 名称: "项目A", 结果: "" },
          { 序号: 2, 代码: "1002", 名称: "项目B", 结果: "" },
          { 序号: 3, 代码: "1003", 名称: "项目C", 结果: "" },
          { 序号: 4, 代码: "1004", 名称: "项目D", 结果: "" },
        ];

        // 加载表格
        function loadTable() {
          table.render({
            elem: "#projectSelect",
            data: selectedProjects,
            cols: [
              [
                { field: "序号", title: "序号", align: "center", width: 60 },
                { field: "代码", title: "代码", align: "center", width: 100 },
                { field: "名称", title: "名称", align: "left", width: 300 },
                {
                  field: "结果",
                  title: "结果",
                  align: "left",
                  width: 250,
                  edit: "text",
                },
              ],
            ],
            height: "full-395",
            done: function () {
              var currDropdown; // 存储当前打开的下拉框
              // 监听表格内所有单元格的 keydown 事件
              $(".layui-table td[data-field='结果']").keydown(function (e) {
                console.log("111");
                if (e.code == "Enter") {
                  isEnter = true;
                }
              });

              $("tr").dblclick(function () {
                var code = $(this).find('td[data-field="代码"]').text();
                var resultoptions = $(this)
                  .find('td[data-field="选项"]')
                  .text();
                var referenceRange = $(this)
                  .find('td[data-field="参考区间"]')
                  .text();
                if (resultoptions) {
                  openOptionDialog(resultoptions, code, function (resultValue) {
                    updateTable("result", code, resultValue, "");
                  });
                }
              });

              // 添加鼠标悬停事件
              $(".layui-table td[data-field='结果']").hover(function () {
                console.log("hover");
                var $this = $(this);
                let options = "张三丰;郭靖;杨过;张无忌";
                // 这里的options应该是动态获取的
                if (options) {
                  $this
                    .attr("contenteditable", "false")
                    .removeAttr("data-edit"); // 禁止编辑并去除 data-edit 属性

                  // 创建下拉框
                  var dropdown = $("<select></select>").css({
                    width: $this.outerWidth(),
                    position: "absolute",
                    zIndex: 1000,
                    backgroundColor: "#fff",
                    border: "1px solid #ddd",
                    padding: "5px",
                  });

                  dropdown.append(
                    $("<option></option>").val("").text("请选择")
                  ); // 默认空选项

                  options.split(";").forEach(function (option) {
                    dropdown.append(
                      $("<option></option>").val(option).text(option)
                    );
                  });

                  // 添加下拉框到单元格
                  $("body").append(dropdown);

                  // 设置下拉框位置
                  console.log("this", $this);
                  var offset = $this.offset();
                  console.log("offset", offset);
                  dropdown.css({
                    top: offset.top + $this.outerHeight(),
                    left: offset.left + 7.5,
                  });

                  // 监听选择事件
                  dropdown.change(function () {
                    var selectedValue = $(this).val();
                    var code = $this
                      .closest("tr")
                      .find('td[data-field="代码"]')
                      .text();
                    updateTable("result", code, selectedValue, "");
                    dropdown.remove(); // 移除下拉框
                    $this.text(selectedValue); // 更新单元格文本
                    $this
                      .attr("contenteditable", "true")
                      .attr("data-edit", "text"); // 恢复编辑并重新添加 data-edit 属性
                  });

                  // 移除上一个单元格的下拉框
                  if (currDropdown) {
                    currDropdown.remove();
                  }

                  currDropdown = dropdown;
                } else {
                  $this
                    .attr("contenteditable", "true")
                    .attr("data-edit", "text"); // 恢复编辑并重新添加 data-edit 属性
                }
              });
            },
          });

          // 监听单元格编辑
          table.on("edit(projectFilter)", function (obj) {
            console.log("edit");
            var data = obj.data;
            var code = data.代码;
            var referenceRange = data.参考区间;
            var value = obj.value; // 得到修改后的值
            updateTable("result", code, value, "");

            // 当点击的是回车键时
            if (isEnter) {
              console.log("enter");
              // 当输入完结果这一项时,点击回车键,自动跳转到下一行的结果这一列
              if (obj.field === "结果") {
                // 更新全局变量,存储当前编辑的行索引
                currentEditingRowIndex = $(obj.tr).data("index"); // 获取当前行的索引
                console.log("currentEditingRowIndex", currentEditingRowIndex);
                // 跳转下一行
                goToNextRow();

                $(this).off("keydown"); // 移除键盘事件监听器
              }
            }
          });
        }

        // 定义函数跳转到下一行
        function goToNextRow() {
          // 获取下一个行的索引
          var nextIndex = currentEditingRowIndex + 1;
          // 获取下一个行的 DOM 元素
          var nextRow = $(".layui-table tr[data-index=" + nextIndex + "]");
          if (nextRow.length > 0) {
            // 模拟点击下一个行的结果列单元格
            nextRow.find('td[data-field="结果"]').click();
          }
          isEnter = false; // 把回车事件标识初始化
        }

        //更新结果或标记标记
        function updateTable(type, code, result, mark, printRang) {
          var tableData = table.cache.projectSelect;
          tableData.forEach(function (row) {
            if (row.代码 === code) {
              if (type === "result") {
                row.结果 = result;
              }
            }
          });

          table.reload("projectSelect", {
            data: tableData,
          });
        }

        // 加载表格
        loadTable();
      });
    </script>
  </body>
</html>

因为现在layui使用场景已经很少,且上面注释较为详细,此处就不再过多赘述了。

希望本文对您有所帮助!

感谢阅读w

相关推荐
牛蛙点点申请出战28 分钟前
IconFontViewer -- 一个可以在 Android Studio 中实时预览 IconFont 的插件
android·前端·intellij idea
空中海30 分钟前
03 渲染机制、性能优化与现代 React
javascript·react.js·性能优化
ChalesXavier1 小时前
Fetch API 的基本用法
javascript
是上好佳佳佳呀1 小时前
【前端(十三)】JavaScript 数组与字符串笔记
前端·javascript·笔记
巴沟旮旯儿1 小时前
vite项目配置文件和打包
前端·设计模式
彩票管理中心秘书长1 小时前
Pinia 插件架构与组合式函数:如何让你的 Store 长出“超能力”
前端
彩票管理中心秘书长1 小时前
Pinia 比 Vuex 强在哪?我用同一个模块写了两种实现,你自己看
前端
yingyima1 小时前
用 Cron 加 Webhook 打通自动化工作的任督二脉
前端
JackieDYH1 小时前
CSS Flexbox 与 Grid 的默认行为-布局的底层机制
前端·css·html