热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于react.js:React自定义hook之useClickOutside判断是否点击DOM之外区域

最近在开发业务需要的时候,有一个场景是点击弹窗之外的区域后,执行某些操作。比方咱们罕用的github左上角的搜寻框,当点击了搜寻框之外的区域当前,搜寻框

最近在开发业务需要的时候,有一个场景是点击弹窗之外的区域后,执行某些操作。比方咱们罕用的github左上角的搜寻框,当点击了搜寻框之外的区域当前,搜寻框就会主动勾销搜寻并收缩起来。

通过调研发现应用useRef+浏览器事件绑定能够实现这一需要,并且能够将这一性能形象为自定义hook。

本文将首先介绍如何用传统形式实现这一需要,而后介绍如何形象成自定义hook,最初联合typescript类型,欠缺这一自定义hook。

实现检测点击对象外区域

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

const Demo: React.FC = () => {
  // 应用useRef绑定DOM对象
  const domRef = useRef(null);

  // 组件初始化绑定点击事件
  useEffect(() => {
    const handleClickOutSide = (e: MouseEvent) => {
      // 判断用户点击的对象是否在DOM节点外部
      if (domRef.current?.contains(e.target as Node)) {
        console.log("点击了DOM外面区域");
        return;
      }
      console.log("点击DOM里面区域");
    };
    document.addEventListener("mousedown", handleClickOutSide);
    return () => {
      document.removeEventListener("mousedown", handleClickOutSide);
    };
  }, []);

  return (
    
); }; export default Demo;

代码不难理解,首先咱们在函数式组件外面写了一个长度和宽度都是300像素的正方形,而后创立了一个名为domRef的对象将其绑定到dom节点上,最初在useEffect钩子外面申明handleClickOutSide的办法判断用户是否点击了指定的DOM区域,并应用document.addEventListener办法增加事件监听,组件卸载时清理事件监听。
在实现的过程中,最外围的是利用了Ref对象上的contains办法,通过钻研发现,Node.contains办法是浏览器的原生办法,其次要的作用是判断传入的DOM节点是否为该节点的后辈节点。

应用根本形式实现后,接着封装自定义hook。

封装useClickOutside hook

大家在了解自定义hook时不用心生畏惧,无非就是调用了其余hook的一般函数,上面来看代码实现:

import { RefObject, useEffect } from "react";
const useClickOutside = (ref: RefObject, handler: Function) => {
  useEffect(() => {
    const listener = (event: MouseEvent) => {
      if (!ref.current || ref.current.contains(event.target as HTMLElement)) {
        return;
      }
      handler(event);
    };
    document.addEventListener("click", listener);
    return () => {
      document.removeEventListener("click", listener);
    };
  }, [ref, handler]);
};

export default useClickOutside;

能够看到,代码将判断是否点击了DOM之外区域的逻辑都抽离进去,这样在应用时,只须要把DOM节点传递给useClickOutside即可,自定义hook的第二个参数接管一个回调函数,能够在回调函数外面做各种事件。来看一下应用自定义hook后的代码:

import React, { useRef } from "react";
import useClickOutside from "../hooks/useOnClickOutside";

const Demo: React.FC = () => {
  // 应用useRef绑定DOM对象
  const domRef = useRef(null);

  useClickOutside(domRef, () => {
    console.log("点击了内部区域");
  });

  return (
    
); }; export default Demo;

能够看到,组件的代码失去大大的简化,而且抽离进去的自定义hook能够在其余组件中复用。但到这一步有优化的空间吗?当然有的,那就是在类型定义方面,能够应用泛型进行优化。
在方才编写的useClickOutside自定义hook中,对ref对象的定义是:RefObject,这种定义其实是不合理的,因为HTMLElement不够具体,有可能传入的是HTMLDivElement或者是HTMLAnchorElement,也有可能是HTMLSpanElement,这里咱们能够应用泛型对其加以限度。

应用泛型优化类型定义

import { RefObject, useEffect, useRef } from 'react'

export function useOnClickOutside(
  node: RefObject,
  handler: undefined | (() => void)
) {
  const handlerRef = useRef void)>(handler)
  useEffect(() => {
    handlerRef.current = handler
  }, [handler])

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      if (node.current?.contains(e.target as Node) ?? false) {
        return
      }
      if (handlerRef.current) handlerRef.current()
    }

    document.addEventListener('mousedown', handleClickOutside)

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

优化后的hook里,应用泛型T指代传入的类型继承自HTMLElement,这样在申明ref对象的时候就能够用T指代传入的DOM类型,应用泛型能够增强对传入参数的束缚,大家在我的项目开发中能够多加尝试。
在handleClickOutside办法中,应用了双问号??判断,双问号的意思是如果后面的局部为undefined则返回前面的内容,也就是false。
本文最初完整版的useClickOutside hook借鉴了uniswap开源我的项目
我的项目地址

谢谢浏览,如果感觉不错,欢送点赞o( ̄▽ ̄)d!


推荐阅读
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • 这篇文章给大家讲解如何利用dhtmlxGantt在服务器端集成数据。脚本数据保存如果您已初始化dataProcessor,则用户或以编程方式所做的任何更改都将自动 ... [详细]
  • 我想将Firebase与ReactHooks结合使用。数据结构的想法是:首先从firebase数 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • PHP函数实现分页含文本分页和数字分页【PHP】
    后端开发|php教程PHP,分页后端开发-php教程最近,在项目中要用到分页。分页功能是经常使用的一个功能,所以,对其以函数形式进行了封装。影视网源码带充值系统,vscode配置根 ... [详细]
  • 本文讨论了将HashRouter改为Router后,页面全部变为空白页且没有报错的问题。作者提到了在实际部署中需要在服务端进行配置以避免刷新404的问题,并分享了route/index.js中hash模式的配置。文章还提到了在vueJs项目中遇到过类似的问题。 ... [详细]
  • ps:写的第一个,不足之处,欢迎拍砖---只是想用自己的方法一步步去实现一些框架看似高大上的小功能(比如说模型中的toArraytoJsonsetAtt ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • 详解react组件通讯方式(多种)
    这篇文章主要介绍了详解react组件通讯方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着 ... [详细]
  • React 小白初入门
    推荐学习:React官方文档:https:react.docschina.orgReact菜鸟教程:https:www.runoob.c ... [详细]
  • 通过手机浏览器调用客户端QQ
    php教程|php手册thinkphp代码,代码示例,代码参考,php短信,数据库备份代码,令牌验证,去除代码中的空白和注释调用QQ客户端php教程-php手册可调用iosandr ... [详细]
  • 程序员_阿里Antd藏圣诞节彩蛋 程序员被离职
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了阿里Antd藏圣诞节彩蛋程序员被离职相关的知识,希望对你有一定的参考价值。 ... [详细]
author-avatar
亿达口香糖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有