使用箭头键导航Dropdown.Item时出现parentNode未定义类型错误
Dropdown菜单箭头键导航报错的解决办法
问题描述
我用以下代码实现自定义文本自动填充组件:仅当文本框输入内容匹配到有效选项时,才渲染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
相关产品推荐
相关产品推荐

