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

React自定义带搜索框下拉组件展开时自动聚焦问题求助

下拉框展开时自动聚焦搜索框的问题解决

问题背景

开发带搜索框的下拉组件时,期望下拉框展开时自动聚焦搜索框,但出现以下问题:

  • 首次触发展开事件时,useRef获取的输入框DOM节点为空,聚焦操作失效
  • 再次切换下拉框时,ref已存在,但聚焦仍无效果
  • 尝试用forwardRef包裹输入组件、将ref加入useEffect依赖均未解决,推测核心原因是下拉框展开时输入框尚未完成DOM渲染

解决方案

核心思路是跟踪下拉框的展开状态,在状态变为展开且输入框DOM渲染完成后触发聚焦,具体实现步骤如下:

1. 新增状态跟踪下拉框展开状态

在组件内部添加状态变量,记录下拉框的展开/收起状态:

const [isDropdownOpen, setIsDropdownOpen] = useState(false);

2. 更新onToggle回调,同步展开状态

修改原有的parentToggled函数,同步更新下拉框状态:

const parentToggled = (isOpen) => {
    setIsDropdownOpen(isOpen); // 同步下拉框展开状态
    if (isOpen) {
        const filtered = allParents.filter(option =>
            option.label.toLowerCase().includes(parentSearchTerm.toLowerCase())
        );
        setParentsFiltered(filtered.slice(0, SCROLL_SIZE));
    }
};

3. 用useEffect监听展开状态,完成后执行聚焦

利用useEffect监听展开状态变化,结合requestAnimationFrame确保DOM渲染完成后再执行聚焦:

useEffect(() => {
    if (isDropdownOpen && parentRef.current) {
        // 等待DOM渲染完成后执行聚焦
        requestAnimationFrame(() => {
            parentRef.current.focus();
        });
    }
}, [isDropdownOpen]);

4. 简化输入组件(可选)

react-bootstrap的FormControl本身支持接收ref,无需额外用forwardRef包裹,可直接使用原组件:

<FormControl
    ref={parentRef}
    id="parentInput"
    type="text"
    placeholder="Search..."
    value={parentSearchTerm}
    onChange={handleParentSearch}
/>

修改后核心代码片段

import React, { useState, useEffect, useRef } from 'react';
import { Dropdown, ButtonGroup, FormControl } from 'react-bootstrap';

// 省略其他常量、状态及辅助函数定义

const CompaniesNav = () => {
    const [isDropdownOpen, setIsDropdownOpen] = useState(false);
    const [parentsFiltered, setParentsFiltered] = useState([]);
    const [parentSearchTerm, setParentSearchTerm] = useState('');
    const parentRef = useRef(null);

    const parentToggled = (isOpen) => {
        setIsDropdownOpen(isOpen);
        if (isOpen) {
            const filtered = allParents.filter(option =>
                option.label.toLowerCase().includes(parentSearchTerm.toLowerCase())
            );
            setParentsFiltered(filtered.slice(0, SCROLL_SIZE));
        }
    };

    const handleParentSearch = (e) => {
        setParentSearchTerm(e.target.value);
        // 保留原有搜索过滤逻辑
    };

    useEffect(() => {
        if (isDropdownOpen && parentRef.current) {
            requestAnimationFrame(() => {
                parentRef.current.focus();
            });
        }
    }, [isDropdownOpen]);

    return (
        <>
            <Dropdown as={ButtonGroup} onToggle={parentToggled}>
                <Dropdown.Toggle variant="company" id="dropdown-basic">
                    <div className="dropdown-container">
                        <div className="dropdown-title">Company Parent</div>
                        <div className="dropdown-value">{selectedParent ? selectedParent : "Select..."}</div>
                        <div className="dropdown-clear" onClick={clearParentDropdown}><i className="fa fa-close" /></div>
                        <span className="dropdown-line"></span>
                        <div className="dropdown-caret"><i className="fa fa-chevron-down" /></div>
                    </div>
                </Dropdown.Toggle>

                <Dropdown.Menu variant='company'>
                    <FormControl
                        ref={parentRef}
                        id="parentInput"
                        type="text"
                        placeholder="Search..."
                        value={parentSearchTerm}
                        onChange={handleParentSearch}
                    />
                    <Dropdown.Divider />
                    {parentsFiltered.length !== 0 ? parentsFiltered.map((option) => (
                        <Dropdown.Item eventKey={option.value} key={option.value} onClick={() => filterParent(option.value, option.label)} href="#">{option.label}</Dropdown.Item>
                    )) : <>
                        <Dropdown.Item eventKey="1" href="#">Empty</Dropdown.Item>
                    </>}
                </Dropdown.Menu>
            </Dropdown>
        </>
    );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 12:35:08