React JS实现点击导航外部关闭响应式导航
Hey there! I see you're trying to get your mobile nav to close when users click or tap anywhere outside of it. Let's walk through how to implement this properly in your React component.
Step 1: Add Refs to Track Nav and Hamburger Elements
First, we need references to your navigation component and hamburger icon so we can check if the user clicked inside those areas. We'll also need a new method to handle clicks outside these elements.
Step 2: Add Global Event Listeners
We'll attach mousedown and touchstart listeners to the document when the component mounts, and remove them when it unmounts (to avoid memory leaks).
Step 3: Implement the Outside Click Handler
This function will check if the click/tap happened outside the nav and hamburger. If the mobile nav is open and the click is outside, we'll close it.
Here's your updated component with all these changes:
import React from 'react'; import { bindAll } from 'lodash'; // Assuming you're using lodash for bindAll, adjust if not export default class Header extends React.Component { constructor() { super(); this.state = { mobileOpenNav: false }; // Add the new handler to your bindAll call bindAll(['openMobileNav', 'openContactModal', 'handleClickOutside'], this); // Initialize refs this.navRef = null; this.hamburgerRef = null; } componentDidMount() { // Attach global click/touch listeners document.addEventListener('mousedown', this.handleClickOutside); document.addEventListener('touchstart', this.handleClickOutside); } componentWillUnmount() { // Clean up listeners to prevent memory leaks document.removeEventListener('mousedown', this.handleClickOutside); document.removeEventListener('touchstart', this.handleClickOutside); } handleClickOutside(event) { // Check if the click is inside the nav or hamburger const isInsideNav = this.navRef && this.navRef.contains(event.target); const isInsideHamburger = this.hamburgerRef && this.hamburgerRef.contains(event.target); // If nav is open and click is outside both, close the nav if (this.state.mobileOpenNav && !isInsideNav && !isInsideHamburger) { this.setState({ mobileOpenNav: false }); } } openMobileNav() { this.props.contactModalToggle(false); this.setState({ mobileOpenNav: !this.state.mobileOpenNav }); } openContactModal() { this.props.contactModalToggle(); this.setState({ mobileOpenNav: !this.state.mobileOpenNav }); } render() { const { nav, contactModalToggle, location, logos } = this.props; const { mobileOpenNav } = this.state; return ( <div className="header-wrap"> <div className="header"> <Logo location={location} logoUrls={logos} /> {/* Add ref to Navigation component */} <Navigation ref={(el) => (this.navRef = el)} location={location} nav={nav} contactModalToggle={this.openContactModal} mobileOpen={mobileOpenNav} mobileToggle={this.openMobileNav} /> {/* Add ref to hamburger element */} <div ref={(el) => (this.hamburgerRef = el)} className="hamburger" onClick={this.openMobileNav} > <img src={HamburgerIcon} /> </div> </div> </div> ); } }
Important Notes:
- If your
Navigationcomponent is a functional component, you'll need to wrap it withReact.forwardRefto pass the ref down to its root DOM element. For example:const Navigation = React.forwardRef((props, ref) => { return <div ref={ref} className="navigation">{/* Your nav content */}</div>; }); - Using
mousedowninstead ofclickensures we catch the event before any other click handlers might interfere. - The
touchstartlistener handles mobile touch events so the behavior works on phones/tablets.
That should do it! Now whenever users click or tap outside the mobile nav or hamburger icon, the nav will automatically close.
内容的提问来源于stack exchange,提问作者Filth

