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

如何实现带SCSS样式的可用自定义Select组件?(附故障代码)

修复单选下拉选择器的功能问题

原代码核心问题

  • 用布尔值checked管理单选选中状态,和单选框的字符串值不匹配,导致状态混乱
  • 未通过react-hook-form的register正确绑定表单控件,无法收集表单数据
  • 两个单选框同时设置defaultChecked={checked},初始状态异常
  • 单选框onChange仅切换布尔值,未记录实际选中的选项值
  • 选中选项后未自动收起下拉菜单

修复方案及完整代码

下面是修复后的Select.tsx,保持原有样式的同时解决功能问题:

import styles from "./select.module.scss";
import { useForm } from "react-hook-form";
import { useRef, useState, useEffect } from "react";

interface IFormInput {
  sortType: string;
}

const Select = () => {
  const { register, handleSubmit, watch } = useForm<IFormInput>({
    defaultValues: { sortType: "Freelancer" } // 设置默认选中值
  });
  const [isOpened, setIsOpened] = useState(false);
  const selectedValue = watch("sortType"); // 实时监听选中值
  const dropdownRef = useRef<HTMLSpanElement>(null);

  const onSubmit = (data: IFormInput) => {
    console.log(data);
  };

  // 点击下拉区域外关闭菜单
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
        setIsOpened(false);
      }
    };
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  // 切换下拉展开状态
  const toggleDropdown = () => {
    setIsOpened(!isOpened);
  };

  // 选中选项后关闭下拉
  const handleOptionSelect = () => {
    setIsOpened(false);
  };

  return (
    <div className={styles.select}>
      <p className={styles.pSelect}>Who are creating the ad?</p>
      <div className={styles.body}>
        <span
          ref={dropdownRef}
          className={`dropdown-el ${isOpened ? "expanded" : ""}`}
        >
          {/* 显示当前选中值,作为下拉触发按钮 */}
          <div onClick={toggleDropdown} className="selected-label">
            {selectedValue}
          </div>
          
          <form onSubmit={handleSubmit(onSubmit)}>
            <div className="options">
              <input
                type="radio"
                name="sortType"
                value="Freelancer"
                id="sort-relevance"
                {...register("sortType")}
                onChange={handleOptionSelect}
              />
              <label htmlFor="sort-relevance">Freelancer</label>

              <input
                type="radio"
                name="sortType"
                value="Client"
                id="sort-best"
                {...register("sortType")}
                onChange={handleOptionSelect}
              />
              <label htmlFor="sort-best">Client</label>
            </div>
            {/* 可选:添加提交按钮,或者通过其他方式触发提交 */}
            {/* <button type="submit">Submit</button> */}
          </form>
        </span>
      </div>
    </div>
  );
};

export default Select;

关键修复点说明

  1. 状态与表单绑定:用watch("sortType")实时获取选中值,替代原有的布尔状态,同时通过{...register("sortType")}完成react-hook-form的控件注册
  2. 默认值设置:在useForm中通过defaultValues设置初始选中值,避免手动处理defaultChecked的混乱
  3. 下拉交互优化:添加点击区域外关闭下拉的逻辑,选中选项后自动收起下拉,提升用户体验
  4. 触发区域优化:单独设置选中值显示区域作为下拉触发按钮,避免点击表单区域误触发展开/收起

样式适配提示

确保你的select.module.scss中包含以下类的样式(保持原样式逻辑即可):

  • .dropdown-el:下拉容器的基础样式
  • .dropdown-el.expanded:下拉展开时的样式
  • .selected-label:当前选中值的显示样式(可复用原标签样式)
  • .options:选项列表的容器样式

内容的提问来源于stack exchange,提问作者Artur Zuiev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:35:13