Layui表格行内动态编辑数据实例介绍

发布时间:2021-08-31 20:07:53 作者:chen
来源:亿速云 阅读:204
# Layui表格行内动态编辑数据实例介绍

## 目录
1. [前言](#前言)
2. [Layui简介](#layui简介)
3. [行内编辑功能概述](#行内编辑功能概述)
4. [基础表格渲染](#基础表格渲染)
5. [行内编辑实现方案](#行内编辑实现方案)
   - [5.1 方案一:使用layui内置方法](#方案一使用layui内置方法)
   - [5.2 方案二:自定义编辑组件](#方案二自定义编辑组件)
6. [完整实现示例](#完整实现示例)
   - [6.1 HTML结构](#html结构)
   - [6.2 JavaScript逻辑](#javascript逻辑)
   - [6.3 CSS样式](#css样式)
7. [进阶功能实现](#进阶功能实现)
   - [7.1 数据验证](#数据验证)
   - [7.2 级联更新](#级联更新)
   - [7.3 批量保存](#批量保存)
8. [常见问题与解决方案](#常见问题与解决方案)
9. [性能优化建议](#性能优化建议)
10. [总结](#总结)

## 前言

在Web应用开发中,数据表格是最常用的数据展示组件之一。传统的表格展示需要用户跳转到新页面或弹出对话框进行数据编辑,这种交互方式效率较低。而行内编辑(In-line Editing)技术允许用户直接在表格行中修改数据,极大地提升了操作效率。

本文将以Layui框架为基础,详细介绍如何实现表格行内动态编辑功能,包含基础实现和进阶优化方案。

## Layui简介

Layui(谐音"类UI")是一款采用自身模块规范编写的前端UI框架,遵循原生HTML/CSS/JS的书写与组织形式。其特点包括:

- 轻量级(核心模块不到100KB)
- 按需加载的模块化设计
- 简洁的API设计
- 内置jQuery-like的DOM操作

表格模块(`table`)是Layui的核心组件之一,提供数据渲染、分页、排序等基础功能,同时支持通过扩展实现行内编辑等高级功能。

## 行内编辑功能概述

行内编辑的主要技术特点:

1. **即时切换**:单元格在只读和编辑状态间动态切换
2. **数据绑定**:编辑控件与行数据自动绑定
3. **验证机制**:支持前端数据验证
4. **保存策略**:支持单行保存或批量保存

相比传统编辑方式,行内编辑的优势在于:
- 减少页面跳转
- 提升操作连贯性
- 降低用户认知负担
- 提高数据录入效率

## 基础表格渲染

在实现行内编辑前,首先需要了解Layui表格的基础渲染方法:

```javascript
layui.use(['table'], function(){
  var table = layui.table;
  
  // 渲染表格
  table.render({
    elem: '#demoTable',
    url: '/api/data',
    cols: [[
      {field: 'id', title: 'ID'},
      {field: 'username', title: '用户名'},
      {field: 'email', title: '邮箱'},
      {field: 'status', title: '状态'},
      {title: '操作', toolbar: '#toolbar'}
    ]],
    page: true
  });
});

对应的HTML结构:

<table id="demoTable" lay-filter="demoTable"></table>
<script type="text/html" id="toolbar">
  <a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
</script>

行内编辑实现方案

方案一:使用layui内置方法

Layui提供了table.cachetable.reload方法可以实现简单的行内编辑:

// 监听工具条事件
table.on('tool(demoTable)', function(obj){
  var data = obj.data;
  var layEvent = obj.event;
  
  if(layEvent === 'edit'){
    // 进入编辑状态
    obj.tr.find('td[data-field="username"]').html('<input type="text" value="'+data.username+'">');
    // 更新操作按钮
    obj.tr.find('.layui-table-tool .layui-btn').text('保存').attr('lay-event', 'save');
  } else if(layEvent === 'save'){
    // 获取修改后的值
    var newVal = obj.tr.find('td[data-field="username"] input').val();
    // 更新缓存数据
    obj.update({
      username: newVal
    });
    // 恢复显示状态
    obj.tr.find('td[data-field="username"]').text(newVal);
    // 恢复操作按钮
    obj.tr.find('.layui-table-tool .layui-btn').text('编辑').attr('lay-event', 'edit');
  }
});

方案二:自定义编辑组件

更完善的方案是创建可复用的编辑组件:

// 定义编辑组件
var tableEditor = {
  init: function(tableId) {
    this.tableId = tableId;
    this.bindEvents();
  },
  
  bindEvents: function() {
    var _this = this;
    
    // 监听行单击事件
    layui.table.on('row('+this.tableId+')', function(obj){
      _this.enterEditMode(obj);
    });
    
    // 监听保存事件
    $(document).on('click', '.save-btn', function(){
      _this.saveData(obj);
    });
  },
  
  enterEditMode: function(obj) {
    // 转换为编辑状态
    var fields = ['username', 'email', 'status'];
    fields.forEach(function(field){
      var td = obj.tr.find('td[data-field="'+field+'"]');
      var val = obj.data[field] || '';
      
      // 根据字段类型生成不同编辑器
      if(field === 'status') {
        td.html('<select class="layui-input">'+
                '<option value="1">启用</option>'+
                '<option value="0">禁用</option>'+
                '</select>');
        td.find('select').val(val);
      } else {
        td.html('<input class="layui-input" value="'+val+'">');
      }
    });
    
    // 添加操作按钮
    obj.tr.find('.layui-table-tool').html(''+
      '<a class="layui-btn layui-btn-xs save-btn">保存</a>'+
      '<a class="layui-btn layui-btn-xs layui-btn-primary cancel-btn">取消</a>');
  },
  
  saveData: function(obj) {
    // 收集数据
    var newData = {};
    var tr = obj.tr;
    
    ['username', 'email', 'status'].forEach(function(field){
      newData[field] = tr.find('td[data-field="'+field+'"] input, select').val();
    });
    
    // 更新行数据
    obj.update(newData);
    
    // 退出编辑模式
    this.exitEditMode(obj);
    
    // 发送到服务器
    $.post('/api/update', {
      id: obj.data.id,
      data: newData
    });
  },
  
  exitEditMode: function(obj) {
    // 恢复显示状态
    var tr = obj.tr;
    for(var field in obj.data) {
      tr.find('td[data-field="'+field+'"]').text(obj.data[field]);
    }
    
    // 恢复操作按钮
    tr.find('.layui-table-tool').html('<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>');
  }
};

// 初始化编辑器
tableEditor.init('demoTable');

完整实现示例

HTML结构

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Layui表格行内编辑示例</title>
  <link rel="stylesheet" href="/layui/css/layui.css">
  <style>
    .editing {
      background-color: #f8f8f8;
    }
    .layui-table td {
      position: relative;
    }
    .layui-table td .layui-input {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      border: none;
      padding: 0 10px;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <div class="layui-container">
    <div class="layui-row">
      <div class="layui-col-md12">
        <table id="demoTable" lay-filter="demoTable"></table>
      </div>
    </div>
  </div>
  
  <script type="text/html" id="toolbar">
    <div class="layui-btn-container">
      <button class="layui-btn layui-btn-sm" lay-event="edit">编辑</button>
      <button class="layui-btn layui-btn-sm layui-btn-normal save-btn" style="display:none;">保存</button>
      <button class="layui-btn layui-btn-sm layui-btn-primary cancel-btn" style="display:none;">取消</button>
    </div>
  </script>
  
  <script src="/layui/layui.js"></script>
  <script>
    // JavaScript代码见下一节
  </script>
</body>
</html>

JavaScript逻辑

layui.use(['table', 'jquery', 'layer'], function(){
  var table = layui.table;
  var $ = layui.jquery;
  var layer = layui.layer;
  
  // 渲染表格
  table.render({
    elem: '#demoTable',
    url: '/api/data',
    cols: [[
      {field: 'id', title: 'ID', width: 80},
      {field: 'username', title: '用户名', edit: 'text'},
      {field: 'email', title: '邮箱', edit: 'text'},
      {field: 'status', title: '状态', edit: 'select', templet: function(d){
        return d.status == 1 ? '启用' : '禁用';
      }},
      {title: '操作', width: 180, toolbar: '#toolbar'}
    ]],
    page: true,
    response: {
      statusCode: 200
    },
    parseData: function(res){
      return {
        "code": res.code,
        "msg": res.msg,
        "count": res.count,
        "data": res.data
      };
    }
  });
  
  // 监听工具条事件
  table.on('tool(demoTable)', function(obj){
    var data = obj.data;
    var tr = obj.tr;
    var event = obj.event;
    
    if(event === 'edit'){
      enterEditMode(obj);
    } else if(event === 'save'){
      saveData(obj);
    } else if(event === 'cancel'){
      exitEditMode(obj);
    }
  });
  
  // 进入编辑模式
  function enterEditMode(obj) {
    obj.tr.addClass('editing');
    obj.tr.find('.edit-btn').hide();
    obj.tr.find('.save-btn, .cancel-btn').show();
    
    // 遍历可编辑列
    obj.tr.find('td[data-edit]').each(function(){
      var td = $(this);
      var field = td.data('field');
      var editType = td.data('edit');
      var value = obj.data[field];
      
      // 根据编辑类型创建不同的编辑器
      switch(editType) {
        case 'text':
          td.html('<input class="layui-input" value="'+value+'">');
          break;
        case 'select':
          var options = '';
          if(field === 'status') {
            options = '<option value="1">启用</option><option value="0">禁用</option>';
          }
          td.html('<select class="layui-input">'+options+'</select>');
          td.find('select').val(value);
          break;
      }
    });
  }
  
  // 保存数据
  function saveData(obj) {
    var newData = {};
    var tr = obj.tr;
    
    // 收集修改的数据
    tr.find('td[data-edit]').each(function(){
      var td = $(this);
      var field = td.data('field');
      var editType = td.data('edit');
      
      if(editType === 'text' || editType === 'select') {
        newData[field] = td.find('input, select').val();
      }
    });
    
    // 显示加载中
    var loadIndex = layer.load(2);
    
    // 模拟异步请求
    setTimeout(function(){
      // 更新表格数据
      obj.update(newData);
      
      // 退出编辑模式
      exitEditMode(obj);
      
      layer.close(loadIndex);
      layer.msg('保存成功', {icon: 1});
      
      // 实际项目中这里应该是Ajax请求
      /*
      $.ajax({
        url: '/api/update',
        type: 'POST',
        data: {
          id: obj.data.id,
          data: newData
        },
        success: function(res){
          if(res.code === 0){
            obj.update(newData);
            exitEditMode(obj);
            layer.msg('保存成功', {icon: 1});
          } else {
            layer.msg(res.msg || '保存失败', {icon: 2});
          }
          layer.close(loadIndex);
        }
      });
      */
    }, 800);
  }
  
  // 退出编辑模式
  function exitEditMode(obj) {
    obj.tr.removeClass('editing');
    obj.tr.find('.save-btn, .cancel-btn').hide();
    obj.tr.find('.edit-btn').show();
    
    // 恢复单元格显示
    obj.tr.find('td[data-edit]').each(function(){
      var td = $(this);
      var field = td.data('field');
      td.text(obj.data[field]);
    });
  }
});

CSS样式

/* 编辑状态高亮 */
.layui-table tbody tr.editing td {
  background-color: #f2f2f2;
}

/* 编辑器样式 */
.layui-table td .layui-input {
  border: 1px solid #e6e6e6;
  border-radius: 2px;
  height: 30px;
  line-height: 30px;
}

/* 操作按钮容器 */
.layui-table-tool .layui-btn-container {
  display: flex;
  gap: 5px;
}

/* 响应式调整 */
@media screen and (max-width: 768px) {
  .layui-table-tool .layui-btn {
    padding: 0 5px;
    font-size: 12px;
  }
}

进阶功能实现

数据验证

在保存前对数据进行验证:

function validateData(data) {
  var errors = [];
  
  if(!data.username || data.username.length < 2) {
    errors.push('用户名至少2个字符');
  }
  
  if(!/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(data.email)) {
    errors.push('邮箱格式不正确');
  }
  
  return errors;
}

// 在saveData函数中添加验证
var errors = validateData(newData);
if(errors.length > 0) {
  layer.msg(errors.join('<br>'), {icon: 2});
  return;
}

级联更新

实现字段间的联动更新:

// 监听字段变化
$(document).on('change', '.layui-table td[data-field="type"] select', function(){
  var tr = $(this).closest('tr');
  var type = $(this).val();
  
  // 根据类型设置不同选项
  if(type === '1') {
    tr.find('td[data-field="status"] select').html(''+
      '<option value="1">正常</option>'+
      '<option value="2">暂停</option>');
  } else {
    tr.find('td[data-field="status"] select').html(''+
      '<option value="1">启用</option>'+
      '<option value="0">禁用</option>');
  }
});

批量保存

实现多行编辑后批量保存:

var modifiedRows = [];

// 修改saveData函数
function saveData(obj) {
  // ...原有代码...
  
  // 记录修改的行
  if(!modifiedRows.includes(obj.data.id)) {
    modifiedRows.push(obj.data.id);
  }
}

// 添加批量保存按钮
$('#batchSave').on('click', function(){
  if(modifiedRows.length === 0) {
    layer.msg('没有修改的数据', {icon: 0});
    return;
  }
  
  // 收集所有修改的数据
  var allData = [];
  var cacheData = table.cache['demoTable'];
  
  cacheData.forEach(function(item){
    if(modifiedRows.includes(item.id)) {
      allData.push({
        id: item.id,
        data: {
          username: item.username,
          email: item.email,
          status: item.status
        }
      });
    }
  });
  
  // 发送批量保存请求
  $.ajax({
    url: '/api/batchUpdate',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify(allData),
    success: function(res){
      if(res.code === 0) {
        layer.msg('成功保存'+modifiedRows.length+'条数据', {icon: 1});
        modifiedRows = [];
      } else {
        layer.msg(res.msg || '保存失败', {icon: 2});
      }
    }
  });
});

常见问题与解决方案

问题1:编辑状态下分页导致数据丢失

解决方案: 在分页前检查是否有未保存的修改:

// 监听分页事件
table.on('page(demoTable)', function(obj){
  if(modifiedRows.length > 0) {
    layer.confirm('有未保存的修改,是否继续?', {
      btn: ['继续', '取消']
    }, function(){
      modifiedRows = [];
      obj.curr = obj.curr;
      table.reload('demoTable', {
        page: { curr: obj.curr }
      });
    });
    return false;
  }
});

问题2:大数据量下性能问题

优化方案: 1. 使用虚拟滚动技术 2. 分块渲染 3. 延迟加载非可视区域数据

”`javascript // 示例:延迟加载 table.render({ // …其他参数… limit: 30, done: function(){ //

推荐阅读:
  1. jquery 版本的动态编辑表格 七
  2. jquery 版本的动态编辑表格 五

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

layui

上一篇:jquery标签选择器的应用

下一篇:jQuery怎么实现列表循环滚动效果

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》