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

React中onBlur事件导致下拉框误隐藏,如何实现点击容器外才隐藏子元素

自定义输入组件点击下拉项误触发关闭的解决方案

问题根因

你当前绑定在外层容器的onBlur事件会在任意内部元素失去焦点时触发:点击下拉框内的选项按钮时,输入框会先触发失焦事件,外层的onBlur回调直接把下拉框隐藏,导致按钮的点击逻辑还没执行就被提前隐藏,不符合预期。

修改方案

通过判断失焦后的目标元素是否在组件容器内部,来决定是否隐藏下拉框,具体修改如下:

  1. 引入useRef给外层容器绑定DOM引用,用于做元素包含判断
  2. 重写onBlur回调逻辑,仅当失焦后的新焦点元素不在组件容器内时,才隐藏下拉框

修改后的完整代码:

import { useState, useRef } from 'react';

export const ListBoxInput = ({ label, data, keyName }) => {
  const [selected, setSelected] = useState({ key: null, value: null });
  const [showDropdown, setShowDropdown] = useState(false);
  // 新增容器引用
  const containerRef = useRef(null);

  return (
    <div
      ref={containerRef}
      className='flex items-center space-x-3'
      // 重写onBlur逻辑
      onBlur={(e) => {
        const nextFocusTarget = e.relatedTarget;
        // 新焦点在当前容器内部时,不关闭下拉框
        if (nextFocusTarget && containerRef.current.contains(nextFocusTarget)) {
          return;
        }
        setShowDropdown(false);
      }}
    >
      <label className='block text-sm font-medium text-gray-700'>{label}</label>

      <div className='relative group'>
        <input
          type='text'
          value={selected.key}
          onFocus={() => setShowDropdown(true)}
          onChange={(e) => setSelected({ key: e.target.value, value: null })}
          disabled={!data.length}
          placeholder={!data.length ? 'No data...' : ''}
          className='w-full py-2 pl-3 pr-10 mt-1 text-left bg-white border border-gray-300 rounded-md shadow-sm disabled:opacity-50 focus:outline-none focus:ring-1 focus:ring-brand focus:border-brand sm:text-sm'
        />

        {showDropdown && (
          <div className='absolute z-10 w-full py-1 mt-3 overflow-auto text-base bg-white rounded-md shadow-lg max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none '>
            {data.map((r) => (
              <button
                key={r.id}
                type='button'
                onClick={() => {
                  setSelected({ key: r[keyName], value: r.id });
                  setShowDropdown(false);
                }}
                className='block w-full py-2 pl-3 text-left hover:bg-gray-100 pr-9'
              >
                {r[keyName]}
              </button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
};

说明

  • 点击下拉选项时,按钮属于容器内部元素,onBlur判断后不会执行关闭逻辑,按钮的点击事件会正常执行,选中后主动关闭下拉框,符合预期
  • 点击容器外部空白区域时,失焦后的relatedTarget为null,会正常触发关闭逻辑,符合需求
  • 该方案仅适用于下拉框DOM直接挂载在当前组件容器内部的场景,如果你后续改用Portal把下拉框挂载到body下,需要调整判断逻辑适配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 17:27:02