useClickAway

监听目标元素外的点击事件的 Hook。

基础用法

import { useClickAway } from 'miaoma-rhooks'
import React, { useState, useRef } from 'react'

function Demo() {
    const [counter, setCounter] = useState(0)
    const ref = useRef(null)

    useClickAway(() => {
        setCounter(s => s + 1)
    }, ref)

    return (
        <div>
            <p>点击外部区域计数: {counter}</p>
            <div
                ref={ref}
                style={{
                    width: 200,
                    height: 100,
                    background: '#2196f3',
                    color: '#fff',
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center'
                }}
            >
                目标区域
            </div>
        </div>
    )
}

API

type Target = Element | (() => Element) | React.MutableRefObject<Element> | Element[];

useClickAway(
  onClickAway: (event: MouseEvent | TouchEvent) => void,
  target: Target | Target[],
  eventName?: string | string[]
);

Params

参数 说明 类型 默认值
onClickAway 触发事件的回调函数 (event: MouseEvent | TouchEvent) => void -
target DOM 节点或者 Ref 对象,支持数组 Target | Target[] -
eventName 指定需要监听的事件,支持数组 string | string[] ['mousedown', 'touchstart']

进阶用法

自定义事件

import { useClickAway } from 'miaoma-rhooks'
import React, { useState, useRef } from 'react'

function CustomEventDemo() {
    const [counter, setCounter] = useState(0)
    const ref = useRef(null)

    useClickAway(
        () => {
            setCounter(s => s + 1)
        },
        ref,
        'click'
    )

    return (
        <div>
            <p>点击外部区域计数 (仅监听 click 事件): {counter}</p>
            <div
                ref={ref}
                style={{
                    width: 200,
                    height: 100,
                    background: '#ff9800',
                    color: '#fff',
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center'
                }}
            >
                目标区域
            </div>
        </div>
    )
}

多个目标元素

import { useClickAway } from 'miaoma-rhooks'
import React, { useState, useRef } from 'react'

function MultiTargetDemo() {
    const [counter, setCounter] = useState(0)
    const ref1 = useRef(null)
    const ref2 = useRef(null)

    useClickAway(() => {
        setCounter(s => s + 1)
    }, [ref1, ref2])

    return (
        <div>
            <p>点击两个区域外部计数: {counter}</p>
            <div style={{ display: 'flex', gap: 16 }}>
                <div
                    ref={ref1}
                    style={{
                        width: 100,
                        height: 100,
                        background: '#4caf50',
                        color: '#fff',
                        display: 'flex',
                        justifyContent: 'center',
                        alignItems: 'center'
                    }}
                >
                    区域 1
                </div>
                <div
                    ref={ref2}
                    style={{
                        width: 100,
                        height: 100,
                        background: '#9c27b0',
                        color: '#fff',
                        display: 'flex',
                        justifyContent: 'center',
                        alignItems: 'center'
                    }}
                >
                    区域 2
                </div>
            </div>
        </div>
    )
}

弹窗应用

import { useClickAway } from 'miaoma-rhooks'
import React, { useState, useRef } from 'react'

function PopupDemo() {
    const [visible, setVisible] = useState(false)
    const popupRef = useRef(null)
    const buttonRef = useRef(null)

    useClickAway(() => {
        setVisible(false)
    }, [popupRef, buttonRef])

    return (
        <div>
            <button ref={buttonRef} onClick={() => setVisible(!visible)} style={{ marginBottom: 16 }}>
                {visible ? '关闭' : '打开'}弹窗
            </button>
            {visible && (
                <div
                    ref={popupRef}
                    style={{
                        width: 300,
                        padding: 16,
                        background: '#f5f5f5',
                        border: '1px solid #e0e0e0',
                        borderRadius: 4
                    }}
                >
                    <h4>弹窗内容</h4>
                    <p>点击弹窗外部区域关闭弹窗</p>
                    <p>点击按钮不会关闭弹窗</p>
                </div>
            )}
        </div>
    )
}