尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

jqGrid经典用法全解析:从数据驱动到企业级表格实践

jqGrid经典用法全解析:从数据驱动到企业级表格实践 1. 项目概述为什么jqGrid依然是经典如果你在2010年到2018年间做过Web后台管理系统尤其是基于jQuery的项目那么“jqGrid”这个名字对你来说可能比初恋还刻骨铭心。它不是一个简单的表格插件而是一个时代的缩影承载了无数后端开发者从“手搓表格”到“开箱即用”的第一次震撼体验。即便在今天React、Vue的组件库满天飞Element UI的Table、Ant Design的Table功能强大到令人发指但在一些历史项目维护、特定场景的快速原型开发甚至是一些对jQuery技术栈有强依赖的团队里jqGrid依然是一个绕不开的话题。我之所以想系统地汇总它的用法不是因为怀旧而是因为它的设计思想足够经典。它完整地封装了数据表格的几乎所有核心功能分页、排序、筛选、行内编辑、树形表格、子表格、数据导出。理解jqGrid你不仅是在学一个过时的插件更是在理解一个“数据驱动视图”的早期优秀实践。它的配置化思想、事件驱动模型与现代前端框架的组件设计有异曲同工之妙。很多新手觉得它配置复杂、文档难啃其实是没有抓住它的核心脉络。这篇文章我就以一个老司机的视角带你重新梳理jqGrid的完整用法从最基础的渲染到高级的定制分享那些官方文档里不会写的“踩坑实录”和“性能心法”。2. jqGrid核心设计与架构思想拆解2.1 理解jqGrid的“数据源驱动”模型jqGrid的核心在于它对数据源的抽象。它不关心你的数据是来自一个PHP脚本、一个Java Servlet还是一个.NET的Web API。它只定义了一套数据交互的“协议”。这套协议主要分为两种模式客户端模式和服务器端模式。这是你入门jqGrid必须跨过的第一道坎选错了模式后续所有操作都会事倍功半。客户端模式顾名思义一次性把所有数据从服务器端加载到浏览器内存中后续的分页、排序、筛选等操作全部在浏览器端由JavaScript完成。它的配置关键是datatype: “local”。这种模式适用于数据量小通常建议不超过1000行的场景。优点是响应速度快用户体验流畅因为所有操作无需再次请求服务器。缺点也很明显大数据量下浏览器内存压力大首次加载慢。服务器端模式这是jqGrid在生产环境中最常用、也是最经典的模式。表格只加载当前页的数据分页、排序、筛选等操作都会向服务器发送新的请求由服务器端完成数据处理后返回新的当前页数据。它的配置关键是datatype: “json”或datatype: “xml”并配合url参数指定后端接口地址。这种模式可以处理海量数据是真正的“企业级”用法。它的精髓在于与后端的“约定”jqGrid会通过HTTP GET或POST请求将页码、每页条数、排序列、排序方式、搜索条件等参数以固定的参数名发送给后端后端则需要按照固定的JSON格式返回数据。这里有一个非常重要的实操心得永远不要尝试去修改jqGrid默认的请求参数名和响应格式。虽然它提供了prmNames和jsonReader等配置项让你自定义但除非万不得已比如后端接口是既定的、无法修改的第三方接口否则强烈建议让后端去适配jqGrid的默认规则。这能为你省去大量的调试时间和潜在的兼容性问题。jqGrid的默认请求参数如page当前页、rows每页行数、sidx排序列、sord排序方式以及响应格式中的total总页数、page当前页、records总记录数、rows数据数组已经成为一种事实上的“行业标准”很多后端框架如Spring MVC、ASP.NET都有现成的组件或封装来对接。2.2 配置化与事件化的双引擎jqGrid的另一个经典设计是极致的配置化。几乎所有功能从列定义、工具栏按钮到外观主题都是通过一个庞大的配置对象jQuery(“#grid”).jqGrid({ … })来完成的。这个对象可能包含上百个属性新手一看就头大。但别怕你不需要记住所有。我的经验是把它分成几个核心模块来理解表格基础配置url,datatype,colModel,colNames,viewrecords,rowNum,rowList,pager等。这是表格的骨架。列模型colModel是灵魂。它定义了每一列的数据键name、显示名label、宽度width、对齐方式align、是否可排序sortable、格式化器formatter、编辑器edittype等。formatter是这里面的魔法棒可以把一个原始值比如状态码1格式化成带颜色的文本比如span style“color:green”启用/span。分页与导航栏pager指定分页控件的DOM元素ID。通过jQuery(“#grid”).jqGrid(‘navGrid’, ‘#pager’, …)来为其添加标准的导航按钮增删改查、刷新、导出等。外观与本地化height,width,shrinkToFit,altRows斑马线控制外观。loadui控制加载提示。通过引入额外的语言文件如grid.locale-cn.js来实现中文等本地化。在配置化的基础上jqGrid通过丰富的事件钩子提供了强大的定制能力。例如onSelectRow事件让你在用户点击某行时执行自定义逻辑beforeRequest事件允许你在发送请求前修改参数loadComplete事件在数据加载完成后触发是进行数据后处理的绝佳位置。事件化意味着jqGrid不是一个黑盒你可以在它生命周期的各个节点注入代码实现高度定制化的业务逻辑。注意jqGrid的事件回调函数中this关键字通常指向的是当前表格的DOM元素而不是jqGrid的实例对象。要获取jqGrid的实例方法通常需要使用jQuery(this).jqGrid(‘getGridParam’, …)或直接使用你初始化时保存的变量。这是早期jQuery插件常见的模式与现代框架的this指向有所不同需要适应。3. 从零到一构建你的第一个jqGrid3.1 环境准备与基础依赖要使用jqGrid你需要准备以下“三件套”jQuery库jqGrid是基于jQuery的插件所以jQuery是必须的。建议使用1.7.x及以上版本兼容性更好。jQuery UI库可选但推荐jqGrid的某些高级功能如对话框、日期选择器以及默认的“Redmond”主题依赖于jQuery UI。如果你的项目没有jQuery UIjqGrid也能工作但一些样式和交互可能会缺失。对于现代项目我更倾向于使用不依赖jQuery UI的版本jqGrid提供了jquery.jqGrid.min.js一个文件包含所有核心功能的版本然后搭配Bootstrap等UI框架的主题。jqGrid核心文件包括CSS和JS。通常你需要jquery.jqGrid.min.js和ui.jqgrid.css以及相关的图片文件。此外为了中文支持还需要引入本地化文件grid.locale-cn.js注意必须先于jqGrid核心JS文件引入。一个典型的基础引入顺序如下!-- 1. jQuery -- script src“https://code.jquery.com/jquery-3.6.0.min.js”/script !-- 2. jQuery UI (可选如果使用其主题或组件) -- link rel“stylesheet” href“https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css” script src“https://code.jquery.com/ui/1.12.1/jquery-ui.min.js”/script !-- 3. jqGrid 本地化文件 (必须放在jqGrid核心JS之前) -- script src“/path/to/grid.locale-cn.js”/script !-- 4. jqGrid 核心CSS和JS -- link rel“stylesheet” href“/path/to/ui.jqgrid.css” script src“/path/to/jquery.jqGrid.min.js”/script在HTML中你需要准备两个容器一个用于放表格一个用于放分页栏。table id“jqGrid”/table div id“jqGridPager”/div3.2 基础配置与服务器端数据绑定让我们从一个最经典的服务器端分页例子开始。假设我们有一个用户管理列表后端接口/api/users支持分页查询。jQuery(“#jqGrid”).jqGrid({ // 1. 数据源配置 url: ‘/api/users’, datatype: “json”, // 从服务器接收JSON格式数据 mtype: “GET”, // 请求方法也可以是POST // 2. 列定义 - 这是表格的核心 colModel: [ { label: ‘ID’, name: ‘id’, width: 50, key: true, sorttype: ‘int’ }, { label: ‘用户名’, name: ‘username’, width: 100, editable: true }, { label: ‘邮箱’, name: ‘email’, width: 150, editable: true }, { label: ‘状态’, name: ‘status’, width: 80, formatter: statusFormatter }, { label: ‘创建时间’, name: ‘createTime’, width: 120, sorttype: ‘date’, formatter: ‘date’, formatoptions: { srcformat:‘Y-m-d H:i:s’, newformat:‘Y-m-d’ } } ], // 列标题如果colModel中没有label则用这个 colNames: [‘ID’, ‘用户名’, ‘邮箱’, ‘状态’, ‘创建时间’], // 3. 分页与视图配置 viewrecords: true, // 显示总记录数信息如“第1-10条共100条” rowNum: 10, // 每页默认显示10条 rowList: [10, 20, 30, 50], // 可供用户选择的每页条数下拉选项 pager: “#jqGridPager”, // 指定分页栏的容器 height: ‘auto’, // 表格高度自适应也可设为固定值如300 autowidth: true, // 宽度自适应容器 // 4. 其他常用配置 caption: “用户管理列表”, // 表格标题 sortname: ‘id’, // 默认排序列 sortorder: ‘desc’, // 默认排序方式 loadonce: false, // 非常重要服务器端模式必须为false。true则变为客户端模式。 jsonReader: { // 定义如何解析后端返回的JSON root: “rows”, // 包含实际数据数组的属性名 page: “page”, // 包含当前页码的属性名 total: “total”, // 包含总页数的属性名 records: “records”, // 包含总记录数的属性名 repeatitems: false // 如果为true则要求rows数组中的每个对象属性顺序与colModel严格对应。通常设为false更灵活。 } });配置完成后调用jQuery(“#jqGrid”).jqGrid(‘navGrid’, ‘#jqGridPager’, {…})来为分页栏添加导航按钮。后端接口约定 当表格初始化或用户点击翻页、排序时jqGrid会向url发送请求例如/api/users?page2rows10sidxcreateTimesordasc。 后端需要处理这些参数进行数据库查询并返回如下格式的JSON{ “total”: 5, // 总页数 “page”: 2, // 当前页码 “records”: 48, // 总记录数 “rows”: [ // 当前页的数据数组 { “id”: 11, “username”: “user11”, “email”: “11test.com”, “status”: 1, “createTime”: “2023-10-01 10:00:00” }, { “id”: 12, “username”: “user12”, “email”: “12test.com”, “status”: 0, “createTime”: “2023-10-02 11:00:00” } // … 共10条 ] }3.3 自定义格式化与单元格渲染上面配置中提到了formatter这是jqGrid展示层最强大的功能之一。它允许你将原始数据转换为任何你想要的HTML内容。内置格式化器jqGrid提供了很多内置格式化器如integer、number、date、checkbox、select。使用它们非常方便{ name: ‘price’, width: 80, formatter: ‘number’, formatoptions: { decimalSeparator:“.”, thousandsSeparator:“,”, decimalPlaces: 2, prefix: “” } } { name: ‘isActive’, width: 70, formatter: ‘checkbox’, formatoptions: { disabled: false } }自定义格式化函数对于更复杂的渲染你需要编写自定义函数。例如上面的statusFormatterfunction statusFormatter(cellvalue, options, rowObject) { // cellvalue: 当前单元格的值 // options: 包含rowId, colModel等信息 // rowObject: 当前行的完整数据对象 switch(cellvalue) { case 1: return ‘span class“label label-success”启用/span’; case 0: return ‘span class“label label-danger”禁用/span’; default: return ‘span class“label label-default”未知/span’; } }你甚至可以在格式化后的HTML元素上绑定事件实现点击按钮等交互。但要注意jqGrid在刷新、分页时会重绘表格动态绑定的事件可能会丢失。更稳妥的做法是利用jqGrid的onCellSelect等事件或者在loadComplete事件中统一进行事件委托绑定。实操心得格式化器中的性能陷阱。自定义格式化函数会在表格渲染每一行每一列时被调用。如果函数内部执行了复杂的DOM操作、同步AJAX请求或大量计算在数据行数较多时会严重拖慢表格渲染速度甚至导致浏览器卡死。务必保证格式化函数的逻辑轻量。对于需要根据其他单元格值进行复杂判断的情况尽量在服务器端处理好直接返回渲染所需的最终值或标识客户端格式化器只做简单的字符串拼接。4. 高级功能实战编辑、工具栏与数据操作4.1 行内编辑与表单编辑jqGrid支持两种主要的编辑模式行内编辑和表单编辑。行内编辑双击某行或点击编辑按钮该行变为可编辑状态修改后可以保存或取消。体验类似Excel适合快速批量修改少量字段。表单编辑点击编辑按钮弹出一个模态对话框在表单中编辑数据。适合字段多、需要复杂验证的场景。要启用编辑功能首先需要在colModel中将需要编辑的列的editable属性设为true。然后通过navGrid方法添加编辑相关的按钮。// 添加导航栏按钮并配置编辑选项 jQuery(“#jqGrid”).jqGrid(‘navGrid’, ‘#jqGridPager’, { add: true, edit: true, del: true, search: true, refresh: true }, // 按钮显示选项 // 编辑选项 { closeAfterEdit: true, // 编辑后关闭对话框 reloadAfterSubmit: true, // 提交后刷新表格 beforeShowForm: function(form) { // 在编辑表单显示前可以做一些操作比如修改标题 jQuery(“#dData”, form).hide(); // 隐藏保存并关闭按钮如果需要 } }, // 添加选项 { closeAfterAdd: true, reloadAfterSubmit: true }, // 删除选项 { reloadAfterSubmit: true } );编辑和添加操作jqGrid默认会向url参数指定的地址发送POST请求并通过oper参数来区分操作类型add、edit、del。你需要在后端接口中根据oper值进行相应的增删改查操作。行内编辑的特别配置 要使用行内编辑你需要使用editRow和saveRow方法通常结合自定义按钮或双击事件。// 监听双击事件启动行内编辑 jQuery(“#jqGrid”).on(‘dblclickRow’, function(rowid) { jQuery(this).jqGrid(‘editRow’, rowid, { keys: true, // 按Enter键保存Esc键取消 oneditfunc: function(rowid) { console.log(‘开始编辑行:’ rowid); }, aftersavefunc: function(rowid) { // 保存成功后可以手动向服务器发送更新请求 var rowData jQuery(“#jqGrid”).jqGrid(‘getRowData’, rowid); // … 发送AJAX请求 } }); });4.2 自定义工具栏与批量操作除了标准的导航按钮我们经常需要添加自定义按钮比如“批量导出”、“批量审核”、“批量删除”。方法一使用navButtonAddjQuery(“#jqGrid”).jqGrid(‘navButtonAdd’, ‘#jqGridPager’, { caption: “批量导出”, buttonicon: “ui-icon-arrowthickstop-1-s”, onClickButton: function() { var selectedIds jQuery(“#jqGrid”).jqGrid(‘getGridParam’, ‘selarrrow’); if (selectedIds.length 0) { alert(“请至少选择一行数据”); return; } // 构造请求打开新窗口下载或发送AJAX请求 window.open(‘/api/export?ids‘ selectedIds.join(‘,’)); }, position: “last” });方法二在表格顶部添加自定义工具栏你可以在表格上方创建一个div然后在这个div里添加自己的按钮逻辑更自由。div id“gridToolbar” style“margin-bottom: 10px;” button id“btnBatchDelete” class“btn btn-danger”批量删除/button button id“btnBatchEnable” class“btn btn-success”批量启用/button /divjQuery(“#btnBatchDelete”).on(‘click’, function() { var selIds jQuery(“#jqGrid”).jqGrid(‘getGridParam’, ‘selarrrow’); if (selIds.length 0) return; if (confirm(‘确定要删除选中的 ‘ selIds.length ‘ 条记录吗’)) { // 发送批量删除AJAX请求 jQuery.ajax({ url: ‘/api/users/batch-delete’, method: ‘POST’, data: { ids: selIds }, success: function() { alert(‘删除成功’); jQuery(“#jqGrid”).trigger(‘reloadGrid’); // 刷新表格 } }); } });4.3 树形表格与子表格这是jqGrid非常强大的两个高级特性常用于展示层级数据。树形表格适用于有明确父子层级关系的数据如部门结构、分类树。关键配置是treeGrid: true、treeGridModel: ‘adjacency’或‘nested’以及在colModel中必须有一列treegrid: true作为树形列。数据需要包含层级信息如level、parent、isLeaf、expanded等。配置相对复杂需要后端返回特定结构的数据。子表格在主表格的每一行可以展开一个子表格显示与该行相关的详细信息列表。例如订单列表展开显示订单项。实现原理是当用户点击展开图标时jqGrid会向一个指定的URL通过subGridUrl配置发送请求并将主表当前行的ID作为参数传递然后将返回的数据渲染到子网格中。配置项包括subGrid: true、subGridUrl、subGridModel等。由于这两个功能配置细节繁多且在现代前端开发中更倾向于使用专门的树形组件或通过组件嵌套来实现类似功能这里不展开详细代码。但你需要知道jqGrid具备这种能力在维护老项目时如果遇到知道该朝哪个方向去查阅文档。5. 性能调优与常见问题排查实录5.1 性能优化核心策略当你的jqGrid加载成百上千行数据感觉卡顿时可以尝试以下优化手段坚决使用服务器端分页这是最重要的原则。永远不要让jqGrid一次性加载超过500条数据到客户端。确保loadonce: false并且后端分页查询高效数据库层面使用LIMIT和OFFSET或更好的分页查询方式。精简colModel只定义需要展示和操作的列。每一列都意味着额外的DOM节点和渲染计算。隐藏列可以考虑通过hidden: true隐藏而不是不定义。慎用复杂的自定义格式化器如前所述格式化器在每个单元格渲染时都会执行。避免在格式化器内进行DOM查询、计算密集型操作或同步请求。复杂的渲染逻辑可以移到loadComplete事件中一次性处理。合理设置rowNum不要一味追求单页显示更多数据。根据用户屏幕和业务需求设置一个合理的默认值如20、30。提供rowList让用户选择。启用滚动条替代分页虚拟滚动jqGrid支持设置scroll: 1和一个固定的height同时设置rowNum为一个较大的值如10000并配合loadonce: true客户端模式。这样会创建一个带垂直滚动条的长表格一次性加载所有数据但只渲染可视区域的部分行适合数据量中等几千条且需要快速上下滚动的场景。注意这本质还是客户端模式数据量过大5000依然会卡。优化后端响应确保接口响应速度快数据库查询有索引。返回的JSON数据尽量精简只包含表格需要的字段。启用GZIP压缩。5.2 常见问题与解决方案速查表以下是我在多年使用中积累的“坑位”记录问题现象可能原因解决方案表格不显示数据控制台无报错1.url错误或不可访问。2. 后端返回的JSON格式不符合jsonReader的约定。3.datatype设置错误如本地数据用了‘json’。1. 用浏览器开发者工具的Network面板检查请求是否发出、响应状态码和内容。2. 核对响应JSON的root、page等属性名是否与jsonReader配置一致。3. 将datatype临时改为‘jsonstring’并设置datastr为一个硬编码的正确JSON字符串测试表格是否能正常渲染以排除数据源问题。分页或排序点击后无反应1. 未正确配置pager或分页栏DOM元素不存在。2. 服务器端模式下后端接口没有正确处理page、sidx等参数。3.loadonce被误设为true。1. 检查pager: “#id”中的ID是否与页面元素匹配。2. 查看Network面板点击分页/排序时请求参数是否正确发送后端返回的数据是否正确。3. 确认loadonce: false。列宽度错乱表头对不齐1. 表格容器宽度变化后未重置。2. 混合使用了固定宽度和百分比宽度。3. 页面初始化时表格容器可能隐藏如在Tab页中。1. 在表格初始化后或容器显示后调用jQuery(“#grid”).jqGrid(‘setGridWidth’, parentWidth);重置宽度。2. 尽量使用固定宽度或全部使用百分比并设置autowidth: true。3. 在Tab页切换显示的事件中调用$(window).trigger(‘resize’);或手动触发表格的setGridWidth。自定义按钮或事件不生效1. 事件绑定时机不对在表格初始化完成前绑定了元素。2. jqGrid动态生成的行内元素直接绑定事件无效。1. 将自定义代码放在jqGrid初始化代码之后或放在gridComplete、loadComplete事件中执行。2. 对动态生成的内容使用事件委托jQuery(“#grid”).on(‘click’, ‘.my-btn’, function(){…})。编辑/删除后表格未刷新navGrid配置中未设置reloadAfterSubmit: true或后端成功处理后未返回正确的操作状态。1. 检查编辑/添加/删除的配置对象中是否有reloadAfterSubmit: true。2. 后端提交操作成功后应返回{ “success”: true }或类似的JSONjqGrid默认期望success属性为真才会认为操作成功并刷新。可通过afterSubmit事件自定义响应处理逻辑。中文表头或按钮文字乱码未正确引入中文本地化文件或引入顺序错误。确保script src“grid.locale-cn.js”/script在jquery.jqGrid.min.js之前引入。在Bootstrap等框架下样式混乱jqGrid的CSS与Bootstrap的CSS发生冲突。使用为Bootstrap定制的jqGrid主题CSS文件如ui.jqgrid-bootstrap.css或者使用不依赖jQuery UI的jqGrid版本并手动调整CSS。5.3 与现代前端技术栈的融合在Vue或React项目中你可能会想使用jqGrid。虽然不推荐在新项目中使用但对于老项目迁移或特定需求可以这样做在Vue中使用 在mounted生命周期钩子中初始化jqGrid因为此时DOM已渲染完毕。将配置数据url、colModel放在Vue的data或computed中。在beforeDestroy钩子中可以考虑调用jQuery(“#grid”).jqGrid(‘GridDestroy’);来清理防止内存泄漏。在React中使用 在componentDidMount生命周期方法中初始化jqGrid。使用ref来获取表格容器的DOM节点。同样在componentWillUnmount中进行清理。状态如搜索条件的变化可以通过监听props或state然后调用jqGrid的setGridParam和trigger(‘reloadGrid’)来刷新数据。核心要点将jqGrid视为一个“黑盒”的DOM操作组件由框架管理其容器和生命周期通过jqGrid提供的APIsetGridParam、trigger来控制它避免直接混合操作jQuery和框架的DOM。最后关于jqGrid的学习资源官方文档和GitHub Wiki仍然是最全面的但可能有些杂乱。多动手实践从最简单的例子开始逐步增加复杂度遇到问题多查阅社区如Stack Overflow的历史问答你会发现很多坑前辈们都踩过了。这个经典的插件理解其设计思想远比记住所有API参数更重要。当你掌握了它你也就理解了那个时代Web应用数据展示的典型解决方案。
返回列表