react 中是如何实现 下拉菜单场景, 点击区域外关闭下拉组件?

在 React 中,要实现点击区域外关闭下拉组件,一般可以使用以下几种方法:

  1. 在下拉组件的根元素上监听点击事件,当点击区域不在下拉组件内时,触发关闭下拉组件的操作。这可以通过添加全局点击事件,然后在事件处理程序中判断点击区域是否在下拉组件内来实现。具体实现如下:
import React, { useRef, useEffect } from 'react';

function DropdownMenu(props) {
  const menuRef = useRef(null);

  useEffect(() => {
    function handleClickOutside(event) {
      if (menuRef.current && !menuRef.current.contains(event.target)) {
        props.onClose();
      }
    }

    document.addEventListener('click', handleClickOutside);
    return () => {
      document.removeEventListener('click', handleClickOutside);
    };
  }, [props]);

  return (
    <div ref={menuRef}>
      {/* 下拉菜单内容 */}
    </div>
  );
}
  1. 在下拉组件的父元素上监听点击事件,当点击区域不在下拉组件及其父元素内时,触发关闭下拉组件的操作。具体实现如下:
import React, { useState } from 'react';

function Dropdown(props) {
  const [isOpen, setIsOpen] = useState(false);

  function toggleDropdown() {
    setIsOpen(!isOpen);
  }

  function handleClickOutside(event) {
    if (!event.target.closest('.dropdown')) {
      setIsOpen(false);
    }
  }

  return (
    <div className="dropdown" onClick={handleClickOutside}>
      <button onClick={toggleDropdown}>Toggle Dropdown</button>
      {isOpen && <DropdownMenu onClose={() => setIsOpen(false)} />}
    </div>
  );
}

在上述代码中,我们在 Dropdown 组件的根元素上添加了点击事件处理程序 handleClickOutside,当点击区域不在 .dropdown 元素内时,触发关闭下拉组件的操作。由于 DropdownMenu 组件位于 Dropdown 组件内部,因此当点击下拉菜单时,事件会冒泡到 Dropdown 组件,从而不会触发关闭操作。

  1. 除了上述方法外,还可以使用 useRef 钩子来监听鼠标点击事件。具体实现可以在下拉组件的根元素上使用 ref 属性来获取 DOM 元素的引用,然后在组件挂载时使用 addEventListener 方法绑定 mousedown 事件,最后在事件处理函数中判断鼠标点击的位置是否在下拉组件内,如果不在,则关闭下拉组件。

示例代码如下:

import { useRef, useState, useEffect } from 'react';

function Dropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef(null);

  useEffect(() => {
    function handleClickOutside(event) {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
        setIsOpen(false);
      }
    }

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [dropdownRef]);

  return (
    <div ref={dropdownRef}>
      <button onClick={() => setIsOpen(!isOpen)}>Toggle Dropdown</button>
      {isOpen && (
        <ul>
          <li>Option 1</li>
          <li>Option 2</li>
          <li>Option 3</li>
        </ul>
      )}
    </div>
  );
}

这种方法可以在组件内部处理点击事件,不需要将事件处理函数传递给父组件。但是相对而言代码会比较繁琐,需要手动处理事件绑定和解绑。