react 实现点击其他地方,隐藏列表(点击元素外)

前言:

我们经常封装一些自己的下拉列表组件 或者 弹窗组件。一般 点击按钮显示 列表或 弹窗。再次点击 隐藏或关闭,但 ui库里的下拉列表,点击除了自己本身也能实现隐藏对应的列表。下面我就给大家一个实现思路。

弹窗组件可以用 React Portals 实现:react 官网 createPortal

实现步骤:

这是一个 简单的点击按钮,显示列表。再次点击隐藏。但我的需求是,点击其他地方也隐藏。

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

const MyList = () => {
   
  const [visable, setVisabled] = useState(false);
  return (
    <div>
      <button onClick={
   () => setVisabled(!visable)}>点击显示 列表</button>
      <div style={
   {
    display: visable ? "block" : "none" }}>
        <div>11111</div>
        <div>22222</div>
      </div>
    </div>
  );
};
export default MyList;

可以利用contains 结合 ref(建议用ref,当然也可以用 document方法,给元素加个 id) 。
contains 是 DOM 元素的方法,用于确定一个元素是否包含另一个元素。不包含则执行 关闭/隐藏事件。
还需要 注意的是,需要 给 隐藏、显示的点击事件加个 阻止事件冒泡的方法event.stopPropagation();
阻止事件冒泡方法必须加上!!!

代码如下:

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

const MyList = () => {
   
  const [visable, setVisabled] = useState(false);
  // 下拉列表 ref
  const dropdownRef = useRef(null);

  useEffect(() => {
   
    //实现点击 本元素外的元素时,隐藏下拉列表(点击其他地方隐藏下拉列表)
    function handleOutsideClick(event) {
   
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
   
        setVisabled(false);
      }
    }
    document.addEventListener("click", handleOutsideClick);
    return () => {
   
      document.removeEventListener("click", handleOutsideClick);
    };
  }, []);
  const hanldClick = (event) => {
   
    event.stopPropagation(); // 阻止事件冒泡
    setVisabled(!visable);
  };
  return (
    <div>
      <button onClick={
   hanldClick}>点击显示 列表</button>
      <div ref={
   dropdownRef} style={
   {
    display: visable ? "block" : "none" }}>
        <div>11111</div>
        <div>22222</div>
      </div>
    </div>
  );
};
export default MyList;

核心代码就是这块:
需要注意的是 绑定的事件需要 在 组件卸载时移除。

useEffect(() => {
   
    //实现点击 本元素外的元素时,隐藏下拉列表(点击其他地方隐藏下拉列表)
    function handleOutsideClick(event) {
   
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
   
        setVisabled(false);
      }
    }
    document.addEventListener("click", handleOutsideClick);
    return () => {
   
      document.removeEventListener("click", handleOutsideClick);
    };
  }, []);

类组件就是这样:
只是把useEffetc里的内容 转换成Class语法。componentDidMount 绑定事件,componentWillUnmount移除事件。

import React, {
    Component } from "react";
class MyList extends Component {
   
  constructor(props) {
   
    super(props);
    this.state = {
   
      visible: false
    };
    this.dropdownRef = React.createRef(); // 下拉列表 ref
  }
  componentDidMount() {
   
    // 实现点击本元素外的元素时,隐藏下拉列表(点击其他地方隐藏下拉列表)
    document.addEventListener("click", this.handleOutsideClick);
  }
  componentWillUnmount() {
   
    document.removeEventListener("click", this.handleOutsideClick);
  }
  handleOutsideClick = (event) => {
   
    if (
      this.dropdownRef.current &&
      !this.dropdownRef.current.contains(event.target)
    ) {
   
      this.setState({
    visible: false });
    }
  };
  handleClick = (event) => {
   
    event.stopPropagation(); // 阻止事件冒泡
    this.setState((prevState) => ({
   
      visible: !prevState.visible
    }));
  };
  render() {
   
    const {
    visible } = this.state;
    
    return (
      <div>
        <button onClick={
   this.handleClick}>点击显示列表</button>
        <div
          ref={
   this.dropdownRef}
          style={
   {
    display: visible ? "block" : "none" }}
        >
          <div>11111</div>
          <div>22222</div>
        </div>
      </div>
    );
  }
}
export default MyList;

理论上来说 这个思路在 vue里也适用,只需要转化vue语法。不过vue 有指令库 v-clickoutside。

总结:

题外话:现在ai真的很强大,我类组件的写法就是让ai转换的,竟然完全正确,运行无误!!! 如果简单的组件 可以试试 ai 。比如 chatGPT\文心一言\通义千问。

比如:文心给的 就可以用,编程方面 chatGPT会比文心强,目前 我认为 gpt是独一档的强!
文心一言 提问分享

相关推荐

  1. vue设置自身以外其他区域关闭列表

    2024-02-03 01:08:01       7 阅读
  2. echars图例之后只显示当前数据其他隐藏

    2024-02-03 01:08:01       16 阅读
  3. vue当前盒子以外任意地方隐藏当前盒子

    2024-02-03 01:08:01       41 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-03 01:08:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-03 01:08:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-03 01:08:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-03 01:08:01       20 阅读

热门阅读

  1. Hook 技术 相关的博客链接(还有一些其他的)

    2024-02-03 01:08:01       40 阅读
  2. 组播目的地址

    2024-02-03 01:08:01       33 阅读
  3. 公司就一个后端一个前端,有必要搞微服务吗?

    2024-02-03 01:08:01       32 阅读
  4. MYSQL学习笔记1

    2024-02-03 01:08:01       35 阅读
  5. Excel计算表达式的值

    2024-02-03 01:08:01       39 阅读
  6. HTTP无状态协议和服务器端状态管理

    2024-02-03 01:08:01       29 阅读