3.2 table 与 form 心得:最常用的两大件

table:方法渲染为主,模板列解复杂单元格

table 支持方法渲染与自动渲染两种方式。自动渲染省事,靠页面上的属性声明就能跑起来;但项目稍复杂我就统一改用方法渲染,理由有三:配置集中在 JS 里便于维护,列结构可以按接口返回动态拼装,渲染时机完全可控。

方法渲染的骨架大致是(以官方文档为准):

table.render({
  elem: "#demo",
  url: "/api/list",
  page: true
});

一行声明容器、数据源与分页,其余细节全在配置里生长,这正是方法渲染可维护性的来源。自动渲染我留给了静态演示页和快速原型,正式项目一律方法渲染。

cols 列配置是 table 的灵魂,我把高频用法汇总如下:

配置 用途 注意
模板列 自定义单元格内容 输出 HTML 字符串,注意转义
toolbar 表头工具条与操作按钮 事件监听与模板配合使用
排序 列头点击排序 前端排序与后端排序行为不同
分页 数据分页 大数据量必须配合后端分页
筛选 列显示隐藏 列多时是提升体验的小利器

模板列是我处理复杂单元格的首选:状态徽标、行内操作按钮、两行摘要,都写进模板里返回拼好的 HTML。写的时候要养成转义习惯,用户输入的内容直接拼进 HTML 有 XSS 风险,别省这一步。

大数据量:分页参数与 URL 模式

数据量一大,table 的表现完全取决于分页策略。我的原则是:超过几百行就交给后端分页,前端只渲染当前页,分页参数随请求走,绝不整表拉回前端。URL 模式下分页状态保留在地址里,刷新、回退、分享链接都不丢页码,排查问题时还能直接复现现场,这对维护者是实打实的福利。

几条分页心得:

  • 页码与每页条数交给组件维护,请求里按文档约定的参数名传给后端,前后端口径统一;
  • 每页条数的默认值别拍脑袋,结合列宽与常用屏幕高度定一个舒服的值;
  • 排序、筛选触发重载时保持分页参数语义一致,避免页码与数据错位;
  • 后端分页是原则,前端一次性渲染上千行属于例外,例外要有明确理由。

2.12 的 ajax 自定义请求:统一拦截器项目的福音

2.12 新增了 ajax 自定义请求选项。它解决的是老项目里最常见的别扭:页面通常有一套统一的请求层,自动带 token、统一处理错误码、统一 loading,而表格自己发请求就绕开了这套管道,鉴权头和错误提示都得二次实现。有了 ajax 选项,表格请求可以直接接入项目统一的请求体系,前后行为终于一致。

另外 2.12 还带来了 syncFixedRowHeight,涉及固定列与行高同步的场景在高版本下表现更稳。具体参数与取值以官方文档为准。

form:动态 DOM 之后必须 form.render()

form 的自动渲染依赖 class 声明,页面静态写好的表单打开就能用。但只要在运行时动态插入 DOM——比如请求接口后填充 select 的选项——就必须手动调用 form.render() 重绘,否则页面上要么一片空白,要么还是原生控件。这是我见过最高频的失灵原因,没有之一。

事件监听用 form.on,按 filter 分流:

form.on("submit(demo-filter)", function(data){
  // 只响应 filter 为 demo-filter 的提交
  return false;
});

filter 分流的好处是同一页多个表单互不干扰,监听代码可以分散到各业务模块,不必全局判别是谁触发的。

再补两条小经验:form.render() 可以按类型、按局部容器重绘,不必每次全量刷新,动态内容多的时候能省下不少开销;select 的搜索配置在选项几十个以上时几乎是刚需,开启后用户直接键入即可过滤,体验差距一目了然,具体属性名以官方文档为准。

form 常见失灵速查

失灵现象 原因 处方
select 动态填充后不生效 未重绘 插入 DOM 后调用 form.render()
checkbox 点了没反应 元素是动态生成的 同样重绘对应类型
监听一直不触发 filter 不匹配 核对属性值与 form.on 参数
提交拿不到表单值 未走 form 提交机制 从提交回调的 data 字段取值

select 还支持搜索配置,选项较多时开启搜索能明显改善体验,具体属性名以官方文档为准。