我正在寻找一种方法来检测点击事件是否发生在组件之外,如本文所述。jQuery最接近()用于查看来自单击事件的目标是否将dom元素作为其父元素之一。如果存在匹配项,则单击事件属于其中一个子项,因此不被视为在组件之外。
所以在我的组件中,我想将一个点击处理程序附加到窗口。当处理程序触发时,我需要将目标与组件的 dom 子项进行比较。
click 事件包含像“path”这样的属性,它似乎保存了事件经过的 dom 路径。我不确定要比较什么或如何最好地遍历它,我想有人一定已经把它放在一个聪明的实用函数中......不是吗?
React 16.3+ 中的 Refs 使用发生了变化。
以下解决方案使用 ES6 并遵循最佳实践来绑定以及通过方法设置 ref。
要查看它的实际效果:
挂钩实现:
import React, { useRef, useEffect } from "react"; /** * Hook that alerts clicks outside of the passed ref */ function useOutsideAlerter(ref) { useEffect(() => { /** * Alert if clicked on outside of element */ function handleClickOutside(event) { if (ref.current && !ref.current.contains(event.target)) { alert("You clicked outside of me!"); } } // 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 OutsideAlerter(props) { const wrapperRef = useRef(null); useOutsideAlerter(wrapperRef); return <div ref={wrapperRef}>{props.children}</div>; }
类实现:
import React, { Component } from 'react'; import PropTypes from 'prop-types'; /** * Component that alerts if you click outside of it */ export default class OutsideAlerter extends Component { constructor(props) { super(props); this.wrapperRef = React.createRef(); this.setWrapperRef = this.setWrapperRef.bind(this); this.handleClickOutside = this.handleClickOutside.bind(this); } componentDidMount() { document.addEventListener('mousedown', this.handleClickOutside); } componentWillUnmount() { document.removeEventListener('mousedown', this.handleClickOutside); } /** * Alert if clicked on outside of element */ handleClickOutside(event) { if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) { alert('You clicked outside of me!'); } } render() { return <div ref={this.wrapperRef}>{this.props.children}</div>; } } OutsideAlerter.propTypes = { children: PropTypes.element.isRequired, };