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

ReactJS如何实现自定义下拉菜单取值展示,无需使用select组件

自定义React下拉菜单实现方案

完全可以不依赖原生select组件实现该需求,你的代码存在3个核心问题导致功能失效:

  • 非表单元素(<p>、<section>)没有原生value属性,通过e.target.value无法读取你自定义写的value属性值
  • 事件冒泡冲突:点击下拉箭头的handleToggle事件会冒泡到外层
    ,触发不需要的handleAmount逻辑
  • 缺少选中值的展示渲染逻辑,没有把state里的amount显示到下拉的头部可见位置

修正后的实现代码

// 初始化state建议加上默认值,示例:
// state = {
//   toggle: false,
//   amount: 1 // 默认选中值
// }

handleToggle = (e) => {
  // 阻止事件冒泡,避免触发外层的handleAmount
  e.stopPropagation();
  this.setState({
    toggle: !this.state.toggle,
  });
};

// 直接接收传入的选中数值,不用从事件对象读取
handleAmount = (value) => {
  this.setState({
    amount: value,
    toggle: false, // 选中后关闭下拉
  });
};

render() {
  // 生成选中值显示文本
  const selectedText = `${this.state.amount} ${this.state.amount === 1 ? 'WHALE' : 'WHALES'}`;
  return (
    <section className="dropdown-wrapper">
      {/* 下拉头部:显示选中值 + 箭头 */}
      <section className="dropdown-header">
        <span>{selectedText}</span>
        <section
          className="arrow-down"
          onClick={this.handleToggle}
        ></section>
      </section>
      {/* 下拉选项列表,根据toggle状态控制显隐 */}
      <section className="dropdown-list" style={{display: this.state.toggle ? 'block' : 'none'}}>
        <p
          onClick={() => this.handleAmount(1)}
          className={this.state.amount === 1 ? 'selected' : ''}
        >
          1 WHALE
        </p>
        <p
          onClick={() => this.handleAmount(2)}
          className={this.state.amount === 2 ? 'selected' : ''}
        >
          2 WHALES
        </p>
        {/* 剩下3、4、5的选项按同样逻辑补充即可 */}
      </section>
    </section>
  )
}

核心优化点

  • 取消了外层不必要的点击事件绑定,直接给每个选项绑定点击事件并显式传入对应数值,规避了非标准属性读取的问题
  • 给箭头点击事件增加e.stopPropagation()阻止冒泡,避免冲突
  • 单独封装下拉头部区域,直接把选中值渲染到头部,用户选中后可以立刻看到更新效果
  • 用toggle状态直接控制下拉列表的显隐,比修改className更直观

内容的提问来源于stack exchange,提问作者Jossif Elefteriadis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:06:00