React JS实现点击菜单外区域关闭悬浮菜单的方法
实现点击外部关闭React悬浮菜单的两种方案
无需useRef的类组件实现
对于类组件,你可以通过监听document的点击事件,结合事件冒泡机制实现需求,不需要用到useRef:
- 管理全局点击监听生命周期:组件挂载时注册
document点击事件,卸载时移除,避免内存泄漏。 - 阻止菜单内部点击冒泡:给悬浮菜单容器添加
onClick事件,阻止事件冒泡到document,确保点击菜单内部不会触发关闭逻辑。 - 判断点击区域:在全局点击事件中,检查点击目标是否属于菜单元素之外,若是且菜单处于打开状态,则关闭菜单。
修改后的代码示例:
class SectionMenu extends Component { state = { isOpen: false, activeSection: '', sectionIds: [], coordinates: [] } componentDidMount() { document.addEventListener('click', this.handleOutsideClick); } componentWillUnmount() { document.removeEventListener('click', this.handleOutsideClick); } handleOutsideClick = (e) => { const menuElement = document.getElementById('floating-menu'); if (menuElement && !menuElement.contains(e.target) && this.state.isOpen) { this.setState({ isOpen: false }); } } handleMenuClick = (e) => { e.stopPropagation(); } render() { const { sections, hideMenu } = this.props; const { sectionIds, isOpen } = this.state; return ( <React.Fragment> <FloatingMenu id="floating-menu" slideSpeed={10} direction="left" isOpen={isOpen} spacing={16} style={hideMenu ? { display: "none" } : null} onClick={this.handleMenuClick} > <MainButton iconResting={} iconActive={} onClick={() => this.setState({ isOpen: !isOpen })} size={} /> {"Random Code to bring up each menu item"} </FloatingMenu> </React.Fragment> ) } }
使用useRef/useEffect的函数组件实现
如果项目倾向于函数组件+Hooks,可通过useRef获取菜单DOM元素,useEffect管理全局监听的生命周期:
import React, { useState, useRef, useEffect } from 'react'; const SectionMenu = ({ sections, hideMenu }) => { const [isOpen, setIsOpen] = useState(false); const [activeSection, setActiveSection] = useState(''); const [sectionIds, setSectionIds] = useState([]); const [coordinates, setCoordinates] = useState([]); const menuRef = useRef(null); useEffect(() => { const handleOutsideClick = (e) => { if (menuRef.current && !menuRef.current.contains(e.target) && isOpen) { setIsOpen(false); } }; document.addEventListener('click', handleOutsideClick); return () => document.removeEventListener('click', handleOutsideClick); }, [isOpen]); const handleMenuClick = (e) => { e.stopPropagation(); }; return ( <React.Fragment> <FloatingMenu ref={menuRef} slideSpeed={10} direction="left" isOpen={isOpen} spacing={16} style={hideMenu ? { display: "none" } : null} onClick={handleMenuClick} > <MainButton iconResting={} iconActive={} onClick={() => setIsOpen(!isOpen)} size={} /> {"Random Code to bring up each menu item"} </FloatingMenu> </React.Fragment> ); };
这种方式通过useRef直接关联菜单元素,比依赖DOM ID更符合React组件化思想,避免潜在的ID冲突问题。
内容的提问来源于stack exchange,提问作者Prateek Sinha
相关产品推荐
相关产品推荐

