我正在寻找一种方法来检测单击事件是否发生在组件之外,如本文所述。jQueryclosest()用于查看单击事件的目标是否将dom元素作为其父元素之一。如果存在匹配项,则单击事件属于其中一个子项,因此不被视为在组件之外。

因此,在我的组件中,我想将一个单击处理程序附加到窗口。当处理程序启动时,我需要将目标与组件的dom子级进行比较。

click事件包含类似“path”的财产,它似乎保存了事件经过的dom路径。我不知道该比较什么,或者如何最好地遍历它,我想肯定有人已经把它放在了一个聪明的效用函数中。。。不


当前回答

import ReactDOM from 'react-dom' ;

class SomeComponent {

  constructor(props) {
    // First, add this to your constructor
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

  componentWillMount() {
    document.addEventListener('mousedown', this.handleClickOutside, false); 
  }

  // Unbind event on unmount to prevent leaks
  componentWillUnmount() {
    window.removeEventListener('mousedown', this.handleClickOutside, false);
  }

  handleClickOutside(event) {
    if(!ReactDOM.findDOMNode(this).contains(event.path[0])){
       console.log("OUTSIDE");
    }
  }
}

其他回答

带打字稿函数Tooltip():ReactElement{const[show,setShow]=useState(false);const-ref=useRef<HTMLDivElement>(null);使用效果(()=>{函数handleClickOutside(事件:MouseEvent):void{if(ref.current&&!ref.current.includes(event.target作为节点)){setShow(false);}}//绑定事件侦听器document.addEventListener('mouseown',handleClickOutside);返回()=>{//清理时取消绑定事件侦听器document.removeEventListener('usedown',handleClickOutside);};});返回(<div ref={ref}></div>) }

你可以用一个简单的方法来解决你的问题,我向你展示:

....

const [dropDwonStatus , setDropDownStatus] = useState(false)

const openCloseDropDown = () =>{
 setDropDownStatus(prev => !prev)
}

const closeDropDown = ()=> {
 if(dropDwonStatus){
   setDropDownStatus(false)
 }
}
.
.
.
<parent onClick={closeDropDown}>
 <child onClick={openCloseDropDown} />
</parent>

这对我有用,祝你好运;)

如果您想使用这个功能已经存在的一个小组件(466字节gzip),那么您可以查看这个库react outclick。

该库的好处在于它还允许您检测组件外部和另一个组件内部的单击。它还支持检测其他类型的事件。

我有一个类似的用例,我必须开发一个自定义下拉菜单。当用户在外面单击时,它应该自动关闭。以下是最近的React Hooks实现-

从“react”导入{useEffect,useRef,useState};导出常量应用程序=()=>{const-ref=useRef();const[isMenuOpen,setIsMenuOpen]=useState(false);使用效果(()=>{常量checkIfClickedOutside=(e)=>{//如果菜单是打开的并且点击的目标不在菜单内,//然后关闭菜单if(isMenuOpen&&ref.current&&!ref.current.contents(e.target)){setIsMenuOpen(false);}};document.addEventListener(“mousedown”,checkIfClickedOutside);返回()=>{//清理事件侦听器document.removeEventListener(“mousedown”,checkIfClickedOutside);};},[isMenuOpen]);返回(<div className=“wrapper”ref={ref}><按钮className=“button”onClick={()=>setIsMenuOpen((oldState)=>!oldState)}>单击我</按钮>{isMenuOpen&&(<ul className=“list”><li className=“list item”>下拉选项1</li><li className=“list item”>下拉选项2</li><li className=“list item”>下拉选项3</li><li className=“list item”>下拉选项4</li></ul>)}</div>);}

在我的DROPDOWN案例中,Ben Bud的解决方案工作得很好,但我有一个单独的切换按钮和一个onClick处理程序。因此,外部单击逻辑与单击切换按钮冲突。下面是我如何通过传递按钮的ref来解决这个问题:

import React, { useRef, useEffect, useState } from "react";

/**
 * Hook that triggers onClose when clicked outside of ref and buttonRef elements
 */
function useOutsideClicker(ref, buttonRef, onOutsideClick) {
  useEffect(() => {

    function handleClickOutside(event) {
      /* clicked on the element itself */
      if (ref.current && !ref.current.contains(event.target)) {
        return;
      }

      /* clicked on the toggle button */
      if (buttonRef.current && !buttonRef.current.contains(event.target)) {
        return;
      }

      /* If it's something else, trigger onClose */
      onOutsideClick();
    }

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

/**
 * Component that alerts if you click outside of it
 */
export default function DropdownMenu(props) {
  const wrapperRef = useRef(null);
  const buttonRef = useRef(null);
  const [dropdownVisible, setDropdownVisible] = useState(false);

  useOutsideClicker(wrapperRef, buttonRef, closeDropdown);

  const toggleDropdown = () => setDropdownVisible(visible => !visible);

  const closeDropdown = () => setDropdownVisible(false);

  return (
    <div>
      <button onClick={toggleDropdown} ref={buttonRef}>Dropdown Toggler</button>
      {dropdownVisible && <div ref={wrapperRef}>{props.children}</div>}
    </div>
  );
}