美文网首页React前端技巧
点击 React组件 以外的其他地方执行相应操作

点击 React组件 以外的其他地方执行相应操作

作者: Lia代码猪崽 | 来源:发表于2021-01-06 17:18 被阅读0次

    场景分析

    比如说是有个按钮 <button/> ,点击这个按钮会出现下拉框 <Select /> ,想点击除了下拉框其他的地方能关闭下拉框。

    技术拆解

    1. 先写好只能由按钮控制显示隐藏

    import React, { useState } from "react";
    
    function Select({ onSelect }) {
      const data = ["春", "夏", "秋", "东"];
      return (
        <ul
          style={{
            background: "#fff",
            color: "#333",
            width: "200px",
            border: "1px solid #999",
            position: "absolute",
            left: "35px",
            top: "15px",
          }}
        >
          {data.map((item) => (
            <li key={item} onClick={() => onSelect(item)}>
              {item}
            </li>
          ))}
        </ul>
      );
    }
    
    function App() {
      const [showSelect, setShowSelect] = useState(false);
      const [season, setSeason] = useState("");
    
      const clickButton = () => {
        setShowSelect(!showSelect);
      };
      const onSelect = (item) => {
        setSeason(item);
      };
    
      return (
        <div className="App">
          <div style={{ position: "relative", width: "300px" }}>
            <button onClick={clickButton}>选择现在的季节:</button>
            {season}
            {showSelect && <Select onSelect={onSelect} />}
          </div>
        </div>
      );
    }
    
    export default App;
    
    页面丑请忽略样式
    点击按钮后会出现选择框,但只能通过再点一次按钮才能关闭

    2. 通过给 document 增加点击事件监听来做到点其他地方关闭下拉框

    这里要特别注意,<button/><Select /> 的区域也是在 document 里的,但是如果点击就隐藏下拉框这不是我们想要的结果,所以还需要在监听方法回调里做判断。

    1. 使用 useRef 获取到结点数据 。
    import React, { useState, useRef } from "react";
    
    // ...
    function App() {
      // ...
      const selectRef = useRef(null);
      // ...
      return (
        <div className="App">
          <div style={{ position: "relative", width: "300px" }} ref={selectRef}>
           // ...
      );  
    }
    
    
    1. 使用 useEffect 来给 document 增加点击事件监听。
    import React, { useState, useRef, useEffect } from "react";
    
    //...
    function App() {
      // ...
    
      useEffect(() => {
        if (showSelect) {
          document.addEventListener("click", clickCallback, false);
          return () => {
            document.removeEventListener("click", clickCallback, false);
          };
        }
      }, [showSelect]);
    
      // ...
    }
    
    1. 编写 clickCallback 回调函数。
    import React, { useState, useRef, useEffect } from "react";
    
    //...
    function App() {
      // ...
    
      function clickCallback(event) {
        if (selectRef.current.contains(event.target)) {
          return;
        }
        setShowSelect(false);
      }
    
      // ...
    }
    
    1. 完美,这下点了除 selectRef 以外的地方都会隐藏 <Select /> 了。

    完整代码

    import React, { useState, useRef, useEffect } from "react";
    
    function Select({ onSelect }) {
      const data = ["春", "夏", "秋", "东"];
      return (
        <ul
          style={{
            background: "#fff",
            color: "#333",
            width: "200px",
            border: "1px solid #999",
            position: "absolute",
            left: "35px",
            top: "15px",
          }}
        >
          {data.map((item) => (
            <li key={item} onClick={() => onSelect(item)}>
              {item}
            </li>
          ))}
        </ul>
      );
    }
    
    function App() {
      const [showSelect, setShowSelect] = useState(false);
      const [season, setSeason] = useState("");
      const selectRef = useRef(null);
    
      const clickButton = () => {
        setShowSelect(!showSelect);
      };
      const onSelect = (item) => {
        setSeason(item);
      };
    
      function clickCallback(event) {
        if (selectRef.current.contains(event.target)) {
          return;
        }
        setShowSelect(false);
      }
    
      useEffect(() => {
        if (showSelect) {
          document.addEventListener("click", clickCallback, false);
          return () => {
            document.removeEventListener("click", clickCallback, false);
          };
        }
      }, [showSelect]);
    
      return (
        <div className="App">
          <div style={{ position: "relative", width: "300px" }} ref={selectRef}>
            <button onClick={clickButton}>选择现在的季节:</button>
            {season}
            {showSelect && <Select onSelect={onSelect} />}
          </div>
        </div>
      );
    }
    
    export default App;
    
    

    相关文章

      网友评论

        本文标题:点击 React组件 以外的其他地方执行相应操作

        本文链接:https://www.haomeiwen.com/subject/zsxooktx.html