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

使用箭头键导航Dropdown.Item时出现parentNode未定义类型错误

问题描述

我用以下代码实现自定义文本自动填充组件:仅当文本框输入内容匹配到有效选项时,才渲染Dropdown.Menu及下拉选项列表。但通过Tab键聚焦到下拉菜单后,按箭头键会触发错误:caught TypeError: Cannot read properties of undefined (reading 'parentNode')。需要实现箭头键正常导航,或者直接禁用箭头键的导航行为,之前尝试添加箭头键事件监听器并调用preventDefault()和stopPropagation()没有效果。

原代码

const renderOptions = () => {
        if (textValue === '') {
            return;
        }

        const validOptionsList = options
            .filter((option) => {
                if (option.toLowerCase().trim().includes(textValue.toLowerCase().trim())) {
                    return (option);
                }
            })
            .map((option) =>
                <Dropdown.Item
                onClick={() => handleClick(option)}>
                    {option}
                </Dropdown.Item>);

        if (validOptionsList.length === 0) {
            return;
        }

        return (
            <div>
                <Dropdown>
                <Dropdown.Menu style={{width: textInputRef?.current?.clientWidth}}
                               show={validOptionsList.length > 0}>
                    {validOptionsList}
                </Dropdown.Menu>
                </Dropdown>
            </div>)
    }

 return (
        <div>
            <Form.Control
                style={{width: width}}
                ref={textInputRef}
                type={'text'}
                placeholder={placeHolder}
                onChange={e => setTextValue(e.target.value)}
                value={textValue}
                maxLength={255}
            />
            {renderOptions()}
        </div>
    )

解决方案

方案一:修复箭头键正常导航

报错原因是Ant Design的Dropdown组件默认需要配合Dropdown.Toggle使用,直接单独渲染Dropdown.Menu会导致组件内部状态管理异常,键盘导航时找不到预期的DOM节点。调整代码结构,将文本框作为Dropdown的触发器,让组件正确管理菜单状态:

import { Dropdown, Form } from 'antd';
import { useState, useRef } from 'react';

const AutoCompleteInput = ({ options, width, placeHolder }) => {
    const [textValue, setTextValue] = useState('');
    const textInputRef = useRef(null);

    const handleClick = (option) => {
        setTextValue(option);
    };

    const getValidOptions = () => {
        if (textValue === '') return [];
        return options
            .filter(option => 
                option.toLowerCase().trim().includes(textValue.toLowerCase().trim())
            )
            .map(option => (
                <Dropdown.Item key={option} onClick={() => handleClick(option)}>
                    {option}
                </Dropdown.Item>
            ));
    };

    const dropdownTrigger = (
        <Form.Control
            style={{ width }}
            ref={textInputRef}
            type="text"
            placeholder={placeHolder}
            onChange={e => setTextValue(e.target.value)}
            value={textValue}
            maxLength={255}
        />
    );

    const validOptions = getValidOptions();

    return (
        <Dropdown
            overlay={
                <Dropdown.Menu style={{ width: textInputRef?.current?.clientWidth }}>
                    {validOptions}
                </Dropdown.Menu>
            }
            trigger={['focus', 'click']}
            visible={validOptions.length > 0}
        >
            {dropdownTrigger}
        </Dropdown>
    );
};

export default AutoCompleteInput;

这样调整后,Dropdown组件能正确处理键盘事件逻辑,箭头键导航可以正常使用,不会再出现parentNode未定义的错误。

方案二:禁用箭头键导航行为

如果不需要箭头键导航功能,直接拦截菜单的键盘事件即可。之前的方法无效是因为事件没绑定到正确的DOM元素,改用原生事件监听:

// 在组件内部新增ref和useEffect
const menuRef = useRef(null);

useEffect(() => {
    const menuDom = menuRef.current;
    if (!menuDom) return;

    const blockArrowKeys = (e) => {
        if (['ArrowUp', 'ArrowDown'].includes(e.key)) {
            e.stopPropagation();
            e.preventDefault();
        }
    };

    menuDom.addEventListener('keydown', blockArrowKeys);
    return () => menuDom.removeEventListener('keydown', blockArrowKeys);
}, [options, textValue]);

// 修改renderOptions里的Dropdown.Menu,绑定ref
const renderOptions = () => {
    // ... 原有逻辑不变
    return (
        <div>
            <Dropdown>
                <Dropdown.Menu 
                    ref={menuRef}
                    style={{width: textInputRef?.current?.clientWidth}}
                    show={validOptionsList.length > 0}
                >
                    {validOptionsList}
                </Dropdown.Menu>
            </Dropdown>
        </div>)
}

通过直接给菜单DOM元素绑定keydown事件,拦截上下箭头键的默认行为和事件冒泡,就能避免触发Dropdown内部的键盘导航逻辑,也就不会报错了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:02:46