使用onBlur函数关闭React JS下拉列表



我在React Js上做了一个下拉列表。我希望在使用onBlur功能单击外部时关闭下拉列表。这里的问题是,当单击下拉选项时,它也会关闭,并且不会执行附加到该选项的功能。我想在onBlur函数中添加一个条件,该条件将检查单击的区域是在下拉框内还是在下拉框外,并采取相应的行动,但我不知道如何检查。

我尝试了document.activeElement,但那是选择了整个body元素。

这是我的代码Sandbox链接:https://codesandbox.io/s/intelligent-tdd-zq4qcr?file=/src/App.js:938-941

这是我需要帮助的功能:

const close = (event) => {
// Help me with this function please
// I need to wrap this function in a condition that checks
// if the click was outside the dropdown
let dropdown = event.target.nextSibling;
// If I comment the lines below,
// it updates the number, but doesn't close the dropdown
if (dropdown?.classList.contains("display")) {
dropdown.classList.remove("display");
setOption("");
}
};

单击下拉按钮时,我正在添加一个属性为display: unset的类。默认情况下,显示设置为none

编辑:在我最初的项目中,这些下拉列表的数量是可变的。根据用户的不同,它们可以是两个,也可以是10个。因此,我无法将其保持在该状态,需要使用JavaScript来跟踪单击了哪个下拉列表。

您有一个很好的开始,但缺少一些东西。您可以创建一个状态,让React为您处理它,而不必自己添加/删除类。

此外,如果在div上添加onFocus事件,则可以管理下拉列表何时打开。

export default function App() {
const [option, setOption] = useState("");
const [isOpen, setIsOpen] = useState(false);
const close = () => {
setIsOpen(false);
}
const open = () => {
setIsOpen(true);
}
const selectValue = (event) => {
const value = event.target.value;
setOption(value);
close();
}
return (
<div className="App">
<h2>Option: {option}</h2>
<p>
Dropdown should close when I click outside it
<br />
Option Number should update
</p>
<div className="dropdown" tabIndex={0} onBlur={close} onFocus={open}>
<button onClick={open}>•••</button>
<div className={`list ${isOpen ? "display" : ""} `}>
<ul>
<li value={1} onClick={selectValue}>Option 1</li>
<li value={2} onClick={selectValue}>Option 2</li>
</ul>
</div>
</div>
</div>
);
}

您可以存储打开状态并有条件地添加显示类。要检测div外部的点击,可以向包装器div传递一个ref并使用一个自定义钩子。

请注意,一般情况下,您应该避免直接操作dom,如果您觉得必须这样做,这很可能意味着您应该重新审视您的方法。


function useOnClickOutside(ref, cb) {
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
cb();
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref, cb]);
}
function Dropdown({onSelect, values}) {
const [isOpen, setIsOpen] = useState(false);
const wrapperRef = useRef(null);
const close = () => {
setIsOpen(false);
};
useOnClickOutside(wrapperRef, close);
const toggle = () => {
setIsOpen(prev => !prev)
};

return (
<div className={`dropdown`} tabIndex={0}>
<button onClick={toggle}>•••</button>
<div ref={wrapperRef} style={{zIndex: 999}} className={`list ${isOpen ? 'display' : ''}`}>
<ul>
{values.map(v => <li
key={v}
onClick={() => {
onSelect(v)
setIsOpen(false)
}}>{"Option " + v}</li>)}
</ul>
</div>
</div>
)
}
export default function App() {
const [option, setOption] = useState(null);

return (
<div className="App">
<h2>Option: {option}</h2>
<p>
Dropdown should close when I click outside it
<br/>
Option Number should update
</p>
<Dropdown onSelect={setOption} values={[1, 2, 3]}/>
<Dropdown onSelect={setOption} values={[4, 5, 6]}/>
<Dropdown onSelect={setOption} values={[6, 7, 8]}/>
</div>
);
}

最新更新