json - 使用 HTML 元素(输入、收音机等)递归呈现 JSON 树
问题描述
我对 React 和使用 JSON 结构非常陌生。我正在尝试构建 JSON 树结构的递归渲染,该结构从树中动态渲染单个 HTML 元素(例如单选按钮、下拉菜单等)。我见过其他实现,但它们没有嵌套的 HTML 元素,这些元素不同于 li、ul 等。它们通常在树的下方也没有不同的命名约定(例如属性、选项)。
树看起来像这样:
{
"id": "1",
"name": "Animals",
"color": "#e37939",
"shape": "bounding_box",
"attributes": [
{
"id": "1.1",
"name": "Type",
"type": "radio",
"required": false,
"options": [
{
"id": "1.1.1",
"optionName": "Cats",
"optionValue": "cats",
"options": [.... and so on
};
我最终要实现的是获得一种格式,其中单击“动物按钮”,然后呈现嵌套的单选按钮,如果选择“猫”选项值,它将呈现下一个下拉菜单。我已经设置了一组初始方法,但我不太清楚如何在单击选项时动态呈现下一组嵌套选项。我在这里创建了一个 React fiddle:https ://codesandbox.io/s/vigilant-grothendieck-jknym
最大的挑战是将嵌套递归选项嵌入选项组中。我还没有弄清楚如何做到这一点。
解决方案
我已经为您想要实现的目标创建了一个数据结构,尽管我已经对其进行了一些调整,因为它的某些部分是多余的,但是您仍然可以保留数据结构并在它们之间进行转换。它可以递归地进行到您想要的深度.
const prodList = [
{
id: "1",
name: "Animals",
options: [
{
id: "1.1",
name: "Type",
inputType: "radio",
options: [
{
id: "1.1.1",
name: "Cats",
value: "Cats",
inputType: "select",
options: [
{ id: "1.1.1.1", name: "Siamese Grey", value: "Siamese Grey" },
{ id: "1.1.1.2", name: "Siamese Black", value: "Siamese Black" },
{ id: "1.1.1.3", name: "Siamese Cute", value: "Siamese Cute" },
{ id: "1.1.1.4", name: "House Cat", value: "House Cat" },
{ id: "1.1.1.5", name: "House Cat", value: "House Cat" }
]
},
{ id: "1.1.2", name: "Dogs", value: "Dogs" },
{ id: "1.1.3", name: "Cows", value: "Cows" }
]
}
]
}
];
上面是具有“inputType”属性的数据结构,该属性有助于确定要显示的组件。我们将有一个基本组件、一个无线电组件和一个可以在它们内部相互渲染的每种类型的选择组件。
export default class ProductsPage extends Component {
render() {
let prodItems = prodList.map(p => {
return <MainContentManager data={p} key={p.id} />;
});
return <div>{prodItems}</div>;
}
}
class MainContentManager extends Component {
render() {
let renderObj = null;
renderObj = basicMethod(renderObj, this.props.data);
return (
<div>
<h6> {this.props.data.name}</h6>
{renderObj}
</div>
);
}
}
class RadioButtonManager extends Component {
constructor(props) {
super(props);
this.state = {
activeOptionIndex: 0
};
this.handleInputClick = this.handleInputClick.bind(this);
}
handleInputClick(index) {
this.setState({
activeOptionIndex: index
});
}
render() {
let renderObj = null;
let renderDat = null;
renderDat = this.props.data.options.map((op, index) => {
return (
<label key={op.id}>
<input
type="radio"
onChange={e => {
this.handleInputClick(index);
}}
checked={index == this.state.activeOptionIndex ? true : false}
/>
{op.name}
</label>
);
});
renderObj = basicMethod(renderObj, {
options: [this.props.data.options[this.state.activeOptionIndex]]
});
return (
<div>
<h6> {this.props.data.name}</h6>
{renderDat}
{renderObj}
</div>
);
}
}
class SelectManager extends Component {
constructor(props) {
super(props);
this.state = { value: "", activeOptionIndex: 0 };
this.handleInputClick = this.handleInputClick.bind(this);
}
handleInputClick(value) {
let activeOptionIndex = this.state.activeOptionIndex;
if (this.props.data.options) {
for (let i = 0; i < this.props.data.options.length; i++) {
if (this.props.data.options[i].value == value) {
activeOptionIndex = i;
}
}
}
this.setState({
value: value,
activeOptionIndex: activeOptionIndex
});
}
render() {
let renderObj = null;
let selectOptions = this.props.data.options.map((op, index) => {
return (
<option key={op.value} value={op.value}>
{op.name}
</option>
);
});
renderObj = basicMethod(renderObj, {
options: [this.props.data.options[this.state.activeOptionIndex]]
});
return (
<div>
<select
onChange={e => {
this.handleInputClick(e.target.value);
}}
>
{selectOptions}
</select>
{renderObj}
</div>
);
}
}
function basicMethod(renderObj, data) {
if (data && data.options) {
renderObj = data.options.map(op => {
!op && console.log(data);
let comp = null;
if (op.inputType == "radio") {
comp = <RadioButtonManager data={op} key={op.id} />;
} else if (op.inputType == "select") {
comp = <SelectManager data={op} key={op.id} />;
} else {
comp = <MainContentManager data={op} key={op.id} />;
}
return comp;
});
}
return renderObj;
}
如果不清楚或者你想要它有点不同,请问任何事情。
推荐阅读
- docker - npm install can't find package.json
- excel - Office JS: Is there a way to find the last row with data in on an excel sheet so that i can then copy that information onto another sheet?
- javascript - Failed to execute 'pushState' on 'History'. Function could not be cloned
- c# - Why is Automapper causing a loading delay in Blazor WebAssembly?
- vue.js - Vue:Vue 路由器没有导航到任何路线
- python - 如何使 python discord bot 执行/使用命令
- jakarta-mail - 带有 OpenJDK 11 的 Jakarta Mail:java.util.ServiceConfigurationError: jakarta.mail.Provider: Provider com.sun.mail.imap.IMAPProvider not a subtype
- python - 在列表中查找每个系统出现一次的值
- python-3.x - grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC 终止于:status = StatusCode.UNAVAILABLE
- firebase - 在前端使用 Firebase Firestore 文档 ID 是不是一个坏主意?