用 SpreadJS 数据验证实现省市区三级联动

地址、商品分类、组织架构、费用科目都有一个共同特点:下一级选项取决于上一级选择。用户选了省份,城市列表就不应该再出现其他省的城市;选了城市,区域也应该随之收窄。三级联动 这个 demo 用 SpreadJS 的数据验证、自定义名称和 INDIRECT 函数组合,在普通单元格里实现省份、城市、区域三级下拉。

为什么这个细节重要

级联下拉解决的是数据质量问题。让用户自由输入省市区,后续清洗会很痛苦;让用户从完整城市列表里找,也不够友好。产品经理需要的是更低的填错概率,开发者需要的是一套能维护的数据源结构,业务用户需要的是"我选完上一级,下一级自然变对"。

这个 demo 的优势是它没有写复杂的弹窗控件,而是沿用电子表格里的数据验证能力。用户仍然在单元格里选择,表格仍然可以复制、粘贴、保存,联动规则则由公式引用完成。

这也让它更适合嵌入已有模板。很多企业表单已经围绕行列设计好了权限、导入和导出流程,级联下拉如果仍然发生在单元格内部,就不会破坏原来的工作方式。

SpreadJS 的实现思路

代码创建了一个名为"级联数据源"的工作表,把树形地址数据展开到不同列。第一列存所有省份;每个省份对应一列城市;每个"省份+城市"再对应一列区域。关键是用 sheet.addCustomName 给这些区域命名,并用 GC.Spread.Sheets.CalcEngine.rangesToFormula 生成绝对引用。

复制代码
sourceSheet.name("级联数据源");
​
let prRange = new GC.Spread.Sheets.Range(1, 0, source.length, 1);
sourceSheet.addCustomName(
  "省份",
  "级联数据源!" + GC.Spread.Sheets.CalcEngine.rangesToFormula(
    [prRange], 0, 0,
    GC.Spread.Sheets.CalcEngine.RangeReferenceRelative.allAbsolute,
    false
  )
);

主表三列分别是省份、城市、区域。省份列直接引用名称"省份";城市列使用 INDIRECT 拼出"级联数据源! + 当前行 A 列值";区域列再拼接 A 列和 B 列,找到对应区域列表。

复制代码
let provinceList =
  GC.Spread.Sheets.DataValidation.createFormulaListValidator("级联数据源!省份");
sheet.setDataValidator(1, 0, 10, 1, provinceList);
​
let cityList =
  GC.Spread.Sheets.DataValidation.createFormulaListValidator(
    'INDIRECT("级联数据源!"&$A2)'
  );
sheet.setDataValidator(1, 1, 10, 1, cityList);

可以扩展到哪些场景

省市区只是最容易理解的例子。同样方法可以用于商品大类、中类、小类,部门、岗位、人员,费用一级科目、二级科目、明细科目,设备类型、型号、点位。只要层级清晰、选项数量适中,这种基于数据源表和名称的方案就比较好维护。

需要注意,自定义名称要避免冲突。demo 用"省份+城市"作为区域名称,如果业务里存在重名城市,就要引入编码或更稳定的 key。数据量特别大时,也可以考虑自定义 CellType 或服务端查询式下拉。

实际交付时,还建议监听上级单元格变化并清空下级旧值。否则用户先选了"广东省-广州市",再把省份改成"浙江省",城市列可能还保留旧城市,形成看似合法但业务不一致的组合。如果要支持批量粘贴,也要在粘贴后重新校验三列组合,避免绕过下拉选择产生脏数据。

给开发者的关键词

SpreadJS、DataValidation、createFormulaListValidator、addCustomName、INDIRECT、GC.Spread.Sheets.Range、rangesToFormula、三级联动、省市区下拉、JavaScript 电子表格控件。

小结

三级联动 展示了 SpreadJS 里很"电子表格原生"的交互方式:用数据验证限制输入,用自定义名称管理候选集,用公式把上下级选项连起来。它让表格录入更稳,也让层级数据维护留在工作簿结构里。

相关推荐
静水leo11 小时前
使用 Whistle 拦截接口并模拟后端响应
前端
掘金者阿豪11 小时前
SQL Server数据迁移完成后,凌晨的数据库告警该怎么查?
前端·后端
JudithHuang11 小时前
React 嵌套路由与布局
前端·react.js·arcgis·react·react router
htzyl20611 小时前
前端阶梯——第四十三章、实战二:待办清单To-Do
前端·javascript·html
摹客12 小时前
【3D设计】界面设计中的3D元素:应用场景+5款工具横评(含Three.js)
前端
Hilaku12 小时前
CORS 到底在保护谁?90% 的前端理解错了跨域的本质
前端·javascript·程序员
wno70413 小时前
node.js中使用jquery
前端·node.js·jquery
阿琳a_13 小时前
b-map-viewer:面向 Vue 3 的地图可视化 SDK,从接入到展示再到交互分析
前端·javascript·vue.js·gis·数据可视化·地图
10年前端老司机13 小时前
Agent 商业化困局:热闹的发布会,冷清的付费客户
前端·后端·agent