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是独一档的强!
文心一言 提问分享

你可能感兴趣的:(React,react.js,javascript,前端)