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

React中如何在select框获取焦点时打开下拉选项?

React实现Select框获焦时自动展开下拉选项

我希望在select框获取焦点时自动打开下拉选项,用React Hooks结合useRef实现,尝试了ref.current.click()但没达到预期效果,是不是操作有误?以下是简化代码:

import {useRef, forwardRef} from 'react';

export default function App() {

  const ref = useRef(null);

  return (
    <div className="App">
      <input type="text" name="text" value="" onChange={(e) => console.log(e)} />
      <br />
      <br />
      <SelectBox 
        ref={ref}
      />
    </div>
  );
}

const SelectBox = forwardRef((props, ref) => {
  function onFocus() {
    if(ref.current) {
      ref.current.click();
    }
  }

  return (
    <select
      ref={ref}
      onChange={(e) => console.log(e)}
      onFocus={onFocus}
    >
      <option value="1">Test 1</option>
      <option value="2">Test 2</option>
    </select>
  )
});

问题原因

你当前的写法有两个核心问题:

  1. 部分浏览器对原生select控件的事件行为有限制,直接调用click()无法触发下拉展开;
  2. focus事件触发时调用click()会引发事件冲突,导致下拉展开后立即收起。

可行解决方案

方案1:触发mousedown事件替代click

原生select的下拉展开逻辑对mousedown事件的响应更稳定,能避免事件冲突:

import {useRef, forwardRef} from 'react';

export default function App() {
  const ref = useRef(null);
  return (
    <div className="App">
      <input type="text" name="text" value="" onChange={(e) => console.log(e)} />
      <br />
      <br />
      <SelectBox ref={ref} />
    </div>
  );
}

const SelectBox = forwardRef((props, ref) => {
  function onFocus() {
    if(ref.current) {
      // 用mousedown事件触发下拉展开
      ref.current.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    }
  }

  return (
    <select
      ref={ref}
      onChange={(e) => console.log(e)}
      onFocus={onFocus}
    >
      <option value="1">Test 1</option>
      <option value="2">Test 2</option>
    </select>
  )
});

方案2:添加状态标记避免重复触发

如果担心重复触发下拉逻辑,可以通过状态标记控制仅在首次获焦时执行:

import {useRef, forwardRef, useState} from 'react';

export default function App() {
  const ref = useRef(null);
  return (
    <div className="App">
      <input type="text" name="text" value="" onChange={(e) => console.log(e)} />
      <br />
      <br />
      <SelectBox ref={ref} />
    </div>
  );
}

const SelectBox = forwardRef((props, ref) => {
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);

  function onFocus() {
    if(ref.current && !isDropdownOpen) {
      ref.current.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
      setIsDropdownOpen(true);
    }
  }

  function onBlur() {
    setIsDropdownOpen(false);
  }

  return (
    <select
      ref={ref}
      onChange={(e) => console.log(e)}
      onFocus={onFocus}
      onBlur={onBlur}
    >
      <option value="1">Test 1</option>
      <option value="2">Test 2</option>
    </select>
  )
});

方案3:利用size属性模拟展开(兼容性拉满)

通过动态设置select的size属性,模拟下拉展开效果,适配所有浏览器:

import {useRef, forwardRef, useState} from 'react';

export default function App() {
  const ref = useRef(null);
  return (
    <div className="App">
      <input type="text" name="text" value="" onChange={(e) => console.log(e)} />
      <br />
      <br />
      <SelectBox ref={ref} />
    </div>
  );
}

const SelectBox = forwardRef((props, ref) => {
  const [selectSize, setSelectSize] = useState(1);

  function onFocus() {
    // 设置size为选项总数,模拟下拉展开
    setSelectSize(ref.current?.options.length || 1);
  }

  function onBlur() {
    setSelectSize(1);
  }

  return (
    <select
      ref={ref}
      onChange={(e) => console.log(e)}
      onFocus={onFocus}
      onBlur={onBlur}
      size={selectSize}
    >
      <option value="1">Test 1</option>
      <option value="2">Test 2</option>
    </select>
  )
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 03:36:24