基于JSONForms实现联动下拉框(含API加载选项)的方案咨询
我来帮你搞定这个依赖下拉的需求,用JSON Forms实现完全没问题,尤其是需要从REST API拉取州数据的场景,我给你拆解成几个关键步骤:
1. 定义基础的JSON Schema与初始UISchema
首先得先把表单的数据结构和初始布局定下来,州字段默认设为只读:
1.1 JSON Schema(数据结构)
{ "type": "object", "properties": { "country": { "type": "string", "enum": ["USA", "Canada", "Mexico"], "title": "国家" }, "state": { "type": "string", "title": "州/省" } } }
1.2 UISchema(布局与初始状态)
{ "type": "VerticalLayout", "elements": [ { "type": "Control", "scope": "#/properties/country" }, { "type": "Control", "scope": "#/properties/state", "options": { "readonly": true } } ] }
2. 实现依赖交互逻辑(React绑定为例)
JSON Forms的核心是自定义渲染器,我们可以给州字段写一个自定义控件,用来处理国家选择后的异步数据加载、状态切换和值清空逻辑。下面以React绑定(最常用的场景)为例:
2.1 创建自定义州下拉控件
import React, { useState, useEffect } from 'react'; import { useJsonFormsControl } from '@jsonforms/react'; import { Select, CircularProgress } from '@mui/material'; // 用Material UI举例,可替换为你用的UI库 const DependentStateSelect = () => { // 从JSON Forms获取表单数据、变更方法等核心属性 const { data, handleChange, path } = useJsonFormsControl(); const [stateOptions, setStateOptions] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isReadOnly, setIsReadOnly] = useState(true); // 监听国家字段的变化,触发后续逻辑 useEffect(() => { const selectedCountry = data?.country; // 切换国家时先清空州的选中值和选项 handleChange(path, undefined); setStateOptions([]); if (!selectedCountry) { setIsReadOnly(true); return; } // 选中国家后,开启可编辑状态并加载数据 setIsReadOnly(false); setIsLoading(true); // 调用REST API获取对应国家的州数据 fetch(`/api/states?country=${selectedCountry}`) .then(res => res.json()) .then(states => { // 转换为JSON Forms下拉控件需要的选项格式 const options = states.map(state => ({ label: state.name, value: state.code })); setStateOptions(options); }) .catch(err => console.error('加载州数据失败:', err)) .finally(() => setIsLoading(false)); }, [data?.country, handleChange, path]); return ( <div style={{ position: 'relative' }}> <Select value={data?.state || ''} onChange={(e) => handleChange(path, e.target.value)} disabled={isReadOnly || isLoading} fullWidth displayEmpty > {stateOptions.map(opt => ( <option key={opt.value} value={opt.value}> {opt.label} </option> ))} </Select> {/* 加载状态提示 */} {isLoading && ( <CircularProgress size={20} style={{ position: 'absolute', right: 10, top: '50%', marginTop: -10 }} /> )} </div> ); }; // 定义渲染器匹配规则:只匹配state字段的Control export const dependentStateTester = (uischema, schema) => { return uischema.type === 'Control' && uischema.scope === '#/properties/state'; }; // 导出自定义渲染器 export const DependentStateRenderer = { tester: dependentStateTester, renderer: DependentStateSelect };
2.2 在主组件中注册自定义渲染器
把自定义渲染器和JSON Forms自带的渲染器合并,传入表单组件:
import { JsonForms } from '@jsonforms/react'; import { materialRenderers } from '@jsonforms/material-renderers'; import { useState } from 'react'; import { DependentStateRenderer } from './DependentStateSelect'; import schema from './schema.json'; import uischema from './uischema.json'; const App = () => { const [formData, setFormData] = useState({}); // 合并默认渲染器和自定义渲染器 const renderers = [...materialRenderers, DependentStateRenderer]; return ( <JsonForms schema={schema} uischema={uischema} data={formData} renderers={renderers} onChange={({ data: newData }) => setFormData(newData)} /> ); }; export default App;
3. 核心逻辑说明
- 只读状态切换:未选择国家时保持只读,选中后自动解除只读
- 值清空:每次切换国家时,通过
handleChange(path, undefined)清空州的选中值 - 异步数据加载:依赖
useEffect监听国家字段变化,触发API请求并转换选项格式 - 加载状态反馈:通过
isLoading状态添加加载动画,提升用户体验
4. 其他绑定框架(Vue/Angular)的思路
如果用Vue或Angular绑定的JSON Forms,核心逻辑完全一致:
- 创建自定义组件,监听国家字段的变化
- 调用API获取州数据,更新组件的选项列表和禁用状态
- 将自定义组件注册到JSON Forms的渲染器列表中
比如Vue可以用@jsonforms/vue提供的useJsonFormsControl组合式API,写法和React版本大同小异。
内容的提问来源于stack exchange,提问作者Ankur Ranjan
相关产品推荐
相关产品推荐

