用 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 里很“电子表格原生”的交互方式用数据验证限制输入用自定义名称管理候选集用公式把上下级选项连起来。它让表格录入更稳也让层级数据维护留在工作簿结构里。