React JS实现条件下拉菜单:DnD角色属性值互斥选择需求
DnD角色表生成器:实现属性下拉菜单的互斥选择
需求说明
我正在构建一个DnD(龙与地下城)角色表生成器,需要为6项主属性各创建一个下拉菜单。所有下拉菜单初始可选择值数组为[8,10,12,13,14,15],要求当某一下拉菜单选中某个数值后,该数值在其他下拉菜单中不可选。例如选择力量属性为15后,其他下拉菜单将无法选择15。
当前代码
下拉菜单构建代码
<div> {standardArray.map((stat, index) => { return ( <div key={index}> <Text marginLeft={5}> {stat.name[index]}</Text> <Select placeholder={stat.name[index]} width="90%" marginLeft={3} marginBottom={3} onChange={handleChange} name={"playerStat" + [index]} > Name: {stat.name} {stat.value.map((value, index) => { return ( <option key={index} value={value}> {value} </option> ); })} </Select> </div> ); })} </div>
数组及状态定义代码
function App() { const [count, setCount] = useState(0); const statArray = [8, 10, 12, 13, 14, 15]; const statTitles = ["STR", "CON", "DEX", "INT", "WIS", "CHA"]; const standardArray = [ { id: 1, name: statTitles, value: statArray }, { id: 2, name: statTitles, value: statArray }, { id: 3, name: statTitles, value: statArray }, { id: 4, name: statTitles, value: statArray }, { id: 5, name: statTitles, value: statArray }, { id: 6, name: statTitles, value: statArray }, ]; const [state, setState] = useState({ playerName: "Test", playerSpecies: "", playerClass: "", playerSubclass: "", playerStat0: 15, playerStat1: 14, playerStat2: 13, playerStat3: 10, playerStat4: 8, playerStat5: 12, playerLevel: 1, strModifier: 0, conModifier: 0, dexModifier: 0, intModifier: 0, wisModifier: 0, chaModifier: 0, playerHp: 24, proficiencyBonus: 2, speciesBonus: 0, });
解决方案
核心思路是动态计算每个下拉菜单的可选值:排除其他属性已选中的值,但保留当前属性自身的选中值(允许用户改回原来的选择)。同时简化冗余的数组定义,优化渲染逻辑。
修改后的完整代码
import { useState } from 'react'; // 保留你原有的UI组件引用 import { Text, Select } from 'your-ui-library'; function App() { const statArray = [8, 10, 12, 13, 14, 15]; const statTitles = ["STR", "CON", "DEX", "INT", "WIS", "CHA"]; const [state, setState] = useState({ playerName: "Test", playerSpecies: "", playerClass: "", playerSubclass: "", playerStat0: 15, playerStat1: 14, playerStat2: 13, playerStat3: 10, playerStat4: 8, playerStat5: 12, playerLevel: 1, strModifier: 0, conModifier: 0, dexModifier: 0, intModifier: 0, wisModifier: 0, chaModifier: 0, playerHp: 24, proficiencyBonus: 2, speciesBonus: 0, }); // 处理下拉菜单值变更 const handleChange = (e) => { const { name, value } = e.target; setState(prev => ({ ...prev, [name]: parseInt(value, 10) })); }; return ( <div> {statTitles.map((title, index) => { // 获取当前属性的已选中值 const currentValue = state[`playerStat${index}`]; // 收集其他所有属性的已选中值 const selectedValues = statTitles .filter((_, idx) => idx !== index) .map(idx => state[`playerStat${idx}`]); // 计算当前下拉菜单的可选值:保留自身选中值 + 未被其他属性选中的值 const availableValues = statArray.filter(val => val === currentValue || !selectedValues.includes(val) ); return ( <div key={index}> <Text marginLeft={5}> {title}</Text> <Select placeholder={title} width="90%" marginLeft={3} marginBottom={3} onChange={handleChange} name={`playerStat${index}`} value={currentValue} > {availableValues.map((value, valIndex) => ( <option key={valIndex} value={value}> {value} </option> ))} </Select> </div> ); })} </div> ); } export default App;
关键修改点说明
- 移除冗余数组:删掉重复存储的
standardArray,直接通过statTitles循环生成菜单,减少不必要的数据冗余 - 动态过滤可选值:对每个属性单独计算可选范围,确保已被其他属性选中的值不会出现在当前菜单中,但保留自身当前选中值,支持用户修改选择
- 修复选中状态绑定:明确设置
Select的value属性,确保菜单选中状态与本地状态同步 - 简化状态更新逻辑:通过
name字段精准更新对应属性的状态,同时将字符串值转换为数字类型,避免类型不一致问题
内容的提问来源于stack exchange,提问作者Doctor Garbage
相关产品推荐
相关产品推荐

