You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

关键修改点说明

  1. 移除冗余数组:删掉重复存储的standardArray,直接通过statTitles循环生成菜单,减少不必要的数据冗余
  2. 动态过滤可选值:对每个属性单独计算可选范围,确保已被其他属性选中的值不会出现在当前菜单中,但保留自身当前选中值,支持用户修改选择
  3. 修复选中状态绑定:明确设置Select的value属性,确保菜单选中状态与本地状态同步
  4. 简化状态更新逻辑:通过name字段精准更新对应属性的状态,同时将字符串值转换为数字类型,避免类型不一致问题

内容的提问来源于stack exchange,提问作者Doctor Garbage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:27:08