自定义hook - 双击事件 - useDBClick
1. 问题:
业务场景中同时需要单击、双击事件,但是原生的onDoubleClick触发双击的时候会同时触发单击事件;
2.解决方案:
封装一个自定义hook能独立地触发单击和双击事件;
根据两次点击的间隔是否小于 interval 来判断触发单击双击事件;
// useDBClick.ts
import { MutableRefObject, useEffect, useRef, MouseEvent as RMouseEvent } from 'react'; export interface UseDBClickOptions<T extends HTMLElement> { ref: MutableRefObject<T | undefined | null> | T; onClick?: (e: RMouseEvent<T>) => void; onDBClick?: (e: RMouseEvent<T>) => void; /** * 单位 ms */ interval?: number; } /** * * eg: * useDBClick({ * ref, * onClick: () => {}, * onDBClick: () => {}, * interval: 200 * }); * */ const useDBClick = <T extends HTMLElement = HTMLElement>(options: UseDBClickOptions<T>) => { const { ref, onClick, onDBClick, interval = 200 } = options; if (typeof interval !== 'number' || isNaN(interval)) { throw new Error('Invalid interval type'); } const intervalRef = useRef<number | null>(); const timerRef = useRef<NodeJS.Timeout | null>(); const isDom = (node: any): node is HTMLElement | SVGElement => node instanceof HTMLElement || node instanceof SVGElement; const isRefObject = (obj: any): obj is MutableRefObject<T> => 'current' in obj; const generateElement = (ref: UseDBClickOptions<T>['ref']) => { if (isRefObject(ref)) { if (isDom(ref.current)) { return ref.current; } } if (isDom(ref)) { return ref; } return; };
/**
* 根据两次点击的间隔是否小于 interval 来判断触发单击双击事件
*/ const innerClick = (e: MouseEvent) => { const time = Date.now(); if (typeof intervalRef.current === 'number' && time - intervalRef.current < interval) { // dbclick if (timerRef.current) { clearTimeout(timerRef.current); } timerRef.current = null; intervalRef.current = null; onDBClick?.(e as unknown as RMouseEvent<T>); return; } // click intervalRef.current = time; timerRef.current = setTimeout(() => { onClick?.(e as unknown as RMouseEvent<T>); }, interval); return; }; const listenClick = () => { const element = generateElement(ref); if (!element) { return; } element.addEventListener('click', innerClick); }; const unlistenClick = () => { const element = generateElement(ref); if (!element) { return; } element.removeEventListener('click', innerClick); }; useEffect(() => { listenClick(); return () => { unlistenClick(); }; }, []); }; export default useDBClick;
自定义hook - 双击事件 - useDBClick更多相关文章
JavaScript CSS Vue3 实现一个简单的Loading
配置和使用nvm免安装版本(nvm-noinstall.zip)
HarmonyOS:使用Node-API实现ArkTS与C/C++跨语言交互
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (一):项目简介及安装依赖
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (四):状态码的使用
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (五):POST上传文件的设置
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (六):token的设置
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (七):MongoDB的设置
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (三):Cors的设置及.env文件的设置
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (二):项目文件夹架构及路由的设置
【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (八):API说明(暂时完结,后续考虑将在线版mongoDB变为本地版)
报error:0308010C:digital envelope routines::unsupported错--nodejs版本过高(nvm安装(更换)不同版本nodejs)
小结---安装nvm解决node版本不兼容的问题(node版本切换)