所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

React强大且灵活hooks库——ahooks入门实践之DOM类hook(dom)详解

什么是 ahooks?

ahooks 是一个 React Hooks 库,提供了大量实用的自定义 hooks,帮助开发者更高效地构建 React 应用。其中 DOM 类 hooks 是 ahooks 的一个重要分类,专门用于处理 DOM 相关操作,如事件监听、元素状态、拖拽等。

安装 ahooks

npm install ahooks

DOM 类 hooks 详解

useEventListener – 事件监听器

useEventListener 用于添加事件监听器。

import React, { useState, useRef } from "react";
import { useEventListener } from "ahooks";
import { Card, Button } from "antd";

const UseEventListenerExample = () => {
  const [count, setCount] = useState(0);
  const buttonRef = useRef(null);

  useEventListener(
    "click",
    () => {
      setCount((prev) => prev + 1);
    },
    { target: buttonRef }
  );

  return (
    <Card title="useEventListener 事件监听器">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>点击次数:</strong> {count}
        </p>
      </div>

      <Button ref={buttonRef}>点击我增加计数</Button>
    </Card>
  );
};

useClickAway – 点击外部

useClickAway 用于检测点击元素外部的事件。

import { useClickAway } from "ahooks";
import { useRef, useState } from "react";

function Dropdown() {
  const [visible, setVisible] = useState(false);
  const ref = useRef();

  useClickAway(() => {
    setVisible(false);
  }, ref);

  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button onClick={() => setVisible(!visible)}>下拉菜单</button>
      {visible && (
        <div
          style={{
            position: "absolute",
            top: "100%",
            border: "1px solid #ccc",
          }}
        >
          <div>菜单项 1</div>
          <div>菜单项 2</div>
          <div>菜单项 3</div>
        </div>
      )}
    </div>
  );
}

useDocumentVisibility – 文档可见性

useDocumentVisibility 用于监听文档可见性状态。

import React from "react";
import { useDocumentVisibility } from "ahooks";
import { Card } from "antd";

const UseDocumentVisibilityExample = () => {
  const documentVisibility = useDocumentVisibility();

  return (
    <Card title="useDocumentVisibility 文档可见性">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>当前状态:</strong> {documentVisibility}
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          切换标签页或最小化窗口查看状态变化
        </p>
      </div>
    </Card>
  );
};

useDrop & useDrag – 拖拽

useDropuseDrag 用于处理拖拽操作。

import React, { useState } from "react";
import { useDrop, useDrag } from "ahooks";
import { Card } from "antd";

const UseDropDragExample = () => {
  const [isOver, setIsOver] = useState(false);
  const [isDragging, setIsDragging] = useState(false);

  const dropRef = useDrop({
    onDom: (content) => {
      console.log("拖拽内容:", content);
      setIsOver(false);
    },
    onDragEnter: () => setIsOver(true),
    onDragLeave: () => setIsOver(false),
  });

  const dragRef = useDrag({
    onDragStart: () => setIsDragging(true),
    onDragEnd: () => setIsDragging(false),
  });

  return (
    <Card title="useDrop & useDrag 拖拽">
      <div style={{ display: "flex", gap: 16 }}>
        <div
          ref={dragRef}
          draggable
          onDragStart={(e) => {
            e.dataTransfer.setData("text/plain", "拖拽的内容");
            setIsDragging(true);
          }}
          onDragEnd={() => setIsDragging(false)}
          style={{
            padding: 16,
            backgroundColor: isDragging ? "#e6f7ff" : "#f0f0f0",
            border: "2px dashed #d9d9d9",
            borderRadius: 4,
            cursor: "move",
            userSelect: "none",
          }}
        >
          拖拽我
        </div>

        <div
          ref={dropRef}
          onDragOver={(e) => e.preventDefault()}
          onDrop={(e) => {
            e.preventDefault();
            const data = e.dataTransfer.getData("text/plain");
            console.log("放置的内容:", data);
            setIsOver(false);
          }}
          onDragEnter={(e) => {
            e.preventDefault();
            setIsOver(true);
          }}
          onDragLeave={(e) => {
            e.preventDefault();
            setIsOver(false);
          }}
          style={{
            padding: 16,
            backgroundColor: isOver ? "#f6ffed" : "#f0f0f0",
            border: "2px dashed #d9d9d9",
            borderRadius: 4,
            minHeight: 60,
          }}
        >
          放置区域
        </div>
      </div>
    </Card>
  );
};

useEventTarget – 事件目标

useEventTarget 用于处理表单输入事件。

import React from "react";
import { useEventTarget } from "ahooks";
import { Card, Input, Button } from "antd";

const UseEventTargetExample = () => {
  const [value, { onChange, reset }] = useEventTarget({
    initialValue: "",
  });

  return (
    <Card title="useEventTarget 事件目标">
      <div style={{ marginBottom: 16 }}>
        <Input
          value={value}
          onChange={onChange}
          placeholder="输入内容"
          style={{ marginBottom: 8 }}
        />
        <p>
          <strong>当前值:</strong> {value}
        </p>
      </div>

      <Button onClick={reset}>重置</Button>
    </Card>
  );
};

useExternal – 外部资源

useExternal 用于动态加载外部资源。

import React, { useState } from "react";
import { useExternal } from "ahooks";
import { Card, Button } from "antd";

const UseExternalExample = () => {
  const [path, setPath] = useState("");

  const status = useExternal(path);

  return (
    <Card title="useExternal 外部资源">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>状态:</strong> <b>{status}</b>
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          加载 Bootstrap CSS 查看徽章样式效果
        </p>
      </div>

      <div style={{ marginBottom: 16 }}>
        <div
          className="bd-example flex gap-2"
          style={{ wordBreak: "break-word" }}
        >
          <span className="badge bg-primary">Primary</span>
          <span className="badge bg-secondary">Secondary</span>
          <span className="badge bg-success">Success</span>
          <span className="badge bg-danger">Danger</span>
          <span className="badge bg-warning text-dark">Warning</span>
          <span className="badge bg-info text-dark">Info</span>
          <span className="badge bg-light text-dark">Light</span>
          <span className="badge bg-dark">Dark</span>
        </div>
      </div>

      <div>
        <Button
          onClick={() =>
            setPath(
              "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
            )
          }
          style={{ marginRight: 8 }}
        >
          加载 Bootstrap CSS
        </Button>
        <Button onClick={() => setPath("")}>卸载</Button>
      </div>
    </Card>
  );
};

useTitle – 页面标题

useTitle 用于动态设置页面标题。

import React, { useState } from "react";
import { useTitle } from "ahooks";
import { Card, Input, Button } from "antd";

const UseTitleExample = () => {
  const [title, setTitle] = useState("ahooks 示例");
  useTitle(title);

  return (
    <Card title="useTitle 页面标题">
      <div style={{ marginBottom: 16 }}>
        <Input
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="输入页面标题"
          style={{ marginBottom: 8 }}
        />
        <p>
          <strong>当前标题:</strong> {title}
        </p>
      </div>

      <Button onClick={() => setTitle("ahooks 示例")}>重置标题</Button>
    </Card>
  );
};

useFavicon – 网站图标

useFavicon 用于动态设置网站图标。

import React, { useState } from "react";
import { useFavicon } from "ahooks";
import { Card, Button } from "antd";

const UseFaviconExample = () => {
  const [favicon, setFavicon] = useState("https://ahooks.js.org/favicon.ico");
  useFavicon(favicon);

  return (
    <Card title="useFavicon 网站图标">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>当前图标:</strong> {favicon}
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          查看浏览器标签页图标变化
        </p>
      </div>

      <div>
        <Button
          onClick={() => setFavicon("https://www.google.com/favicon.ico")}
          style={{ marginRight: 8 }}
        >
          设置为 Google 图标
        </Button>
        <Button onClick={() => setFavicon("https://ahooks.js.org/favicon.ico")}>
          恢复默认
        </Button>
      </div>
    </Card>
  );
};

useFullscreen – 全屏

useFullscreen 用于控制全屏状态。

import React, { useRef } from "react";
import { useFullscreen } from "ahooks";
import { Card, Button } from "antd";

const UseFullscreenExample = () => {
  const ref = useRef(null);
  const [isFullscreen, { enterFullscreen, exitFullscreen, toggleFullscreen }] =
    useFullscreen(ref);

  return (
    <Card title="useFullscreen 全屏">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>全屏状态:</strong> {isFullscreen ? "是" : "否"}
        </p>
      </div>

      <div
        ref={ref}
        style={{
          padding: 16,
          backgroundColor: "#f0f0f0",
          border: "1px solid #d9d9d9",
          borderRadius: 4,
          marginBottom: 16,
        }}
      >
        这个区域可以全屏显示
      </div>

      <div>
        <Button onClick={enterFullscreen} style={{ marginRight: 8 }}>
          进入全屏
        </Button>
        <Button onClick={exitFullscreen} style={{ marginRight: 8 }}>
          退出全屏
        </Button>
        <Button onClick={toggleFullscreen}>切换全屏</Button>
      </div>
    </Card>
  );
};

useHover – 悬停状态

useHover 用于检测元素悬停状态。

import React, { useRef } from "react";
import { useHover } from "ahooks";
import { Card } from "antd";

const UseHoverExample = () => {
  const ref = useRef(null);
  const isHovering = useHover(ref);

  return (
    <Card title="useHover 悬停状态">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>悬停状态:</strong> {isHovering ? "悬停中" : "未悬停"}
        </p>
      </div>

      <div
        ref={ref}
        style={{
          padding: 16,
          backgroundColor: isHovering ? "#e6f7ff" : "#f0f0f0",
          border: "1px solid #d9d9d9",
          borderRadius: 4,
          transition: "background-color 0.3s",
        }}
      >
        鼠标悬停我
      </div>
    </Card>
  );
};

useMutationObserver – 元素变化监听

useMutationObserver 用于监听 DOM 元素变化。

import React, { useState, useRef, useCallback } from "react";
import { useMutationObserver } from "ahooks";
import { Card, Button } from "antd";

const UseMutationObserverExample = () => {
  const [changeCount, setChangeCount] = useState(0);
  const ref = useRef(null);

  const handleMutation = useCallback((mutationsList) => {
    mutationsList.forEach(() => setChangeCount((c) => c + 1));
  }, []);

  useMutationObserver(handleMutation, ref, {
    attributes: true,
    childList: true,
    subtree: true,
  });

  const addElement = () => {
    const div = document.createElement("div");
    div.textContent = "新元素";
    ref.current?.appendChild(div);
  };

  const changeAttribute = () => {
    if (ref.current) {
      ref.current.style.backgroundColor = "#e6f7ff";
    }
  };

  return (
    <Card title="useMutationObserver 元素变化监听">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>变化次数:</strong> {changeCount}
        </p>
      </div>

      <div
        ref={ref}
        style={{
          padding: 16,
          backgroundColor: "#f0f0f0",
          border: "1px solid #d9d9d9",
          borderRadius: 4,
          marginBottom: 16,
          minHeight: 60,
        }}
      >
        监听区域
      </div>

      <div>
        <Button onClick={addElement} style={{ marginRight: 8 }}>
          添加元素
        </Button>
        <Button onClick={changeAttribute}>改变属性</Button>
      </div>
    </Card>
  );
};

useInViewport – 视口可见性

useInViewport 用于检测元素是否在视口中可见。

import React, { useRef } from "react";
import { useInViewport } from "ahooks";
import { Card } from "antd";

const UseInViewportExample = () => {
  const ref = useRef(null);
  const [inViewport] = useInViewport(ref);

  return (
    <Card title="useInViewport 视口可见性">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>可见状态:</strong> {inViewport ? "可见" : "不可见"}
        </p>
      </div>

      <div
        style={{ height: 200, overflow: "auto", border: "1px solid #d9d9d9" }}
      >
        <div style={{ height: 100, backgroundColor: "#f0f0f0" }}>
          滚动区域顶部
        </div>

        <div
          ref={ref}
          style={{
            padding: 16,
            backgroundColor: inViewport ? "#f6ffed" : "#fff2e8",
            border: "1px solid #d9d9d9",
            borderRadius: 4,
            margin: 16,
          }}
        >
          监听可见性的元素
        </div>

        <div style={{ height: 300, backgroundColor: "#f0f0f0" }}>
          滚动区域底部
        </div>
      </div>
    </Card>
  );
};

useKeyPress – 键盘按键

useKeyPress 用于监听键盘按键事件。

import React, { useState } from "react";
import { useKeyPress } from "ahooks";
import { Card } from "antd";

const UseKeyPressExample = () => {
  const [pressedKey, setPressedKey] = useState("");

  useKeyPress(["a", "b", "c"], (event) => {
    setPressedKey(event.key);
  });

  return (
    <Card title="useKeyPress 键盘按键">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>按下的键:</strong> {pressedKey || "无"}
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          按下 A、B、C 键查看效果
        </p>
      </div>
    </Card>
  );
};

useLongPress – 长按

useLongPress 用于检测长按事件。

import React, { useState } from "react";
import { useLongPress } from "ahooks";
import { Card } from "antd";

const UseLongPressExample = () => {
  const [message, setMessage] = useState("");

  const longPress = useLongPress(
    () => {
      setMessage("长按触发");
    },
    {
      onCancel: () => {
        setMessage("长按取消");
      },
    },
    {
      delay: 1000,
    }
  );

  return (
    <Card title="useLongPress 长按">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>状态:</strong> {message || "等待长按"}
        </p>
      </div>

      <div
        {...longPress}
        style={{
          padding: 16,
          backgroundColor: "#f0f0f0",
          border: "1px solid #d9d9d9",
          borderRadius: 4,
          cursor: "pointer",
          userSelect: "none",
        }}
      >
        长按我 1 秒
      </div>
    </Card>
  );
};

useMouse – 鼠标位置

useMouse 用于获取鼠标位置。

import React from "react";
import { useMouse } from "ahooks";
import { Card } from "antd";

const UseMouseExample = () => {
  const mouse = useMouse();

  return (
    <Card title="useMouse 鼠标位置">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>X 坐标:</strong> {mouse.clientX}
        </p>
        <p>
          <strong>Y 坐标:</strong> {mouse.clientY}
        </p>
        <p>
          <strong>屏幕 X:</strong> {mouse.screenX}
        </p>
        <p>
          <strong>屏幕 Y:</strong> {mouse.screenY}
        </p>
      </div>

      <div style={{ fontSize: "12px", color: "#666" }}>
        移动鼠标查看坐标变化
      </div>
    </Card>
  );
};

useResponsive – 响应式

useResponsive 用于检测屏幕尺寸。

import React from "react";
import { configResponsive, useResponsive } from "ahooks";
import { Card } from "antd";

configResponsive({
  small: 0,
  middle: 800,
  large: 1200,
});

const UseResponsiveExample = () => {
  const responsive = useResponsive();

  return (
    <Card title="useResponsive 响应式">
      <div style={{ marginBottom: 16 }}>
        <p>请调整浏览器窗口宽度查看效果:</p>
        {Object.keys(responsive).map((key) => (
          <p key={key}>
            <strong>{key}:</strong> {responsive[key] ? "✔" : "✘"}
          </p>
        ))}
      </div>

      <div style={{ fontSize: "12px", color: "#666" }}>
        断点配置: small(0px) | middle(800px) | large(1200px)
      </div>
    </Card>
  );
};

useScroll – 滚动

useScroll 用于监听滚动事件。

import React, { useRef } from "react";
import { useScroll } from "ahooks";
import { Card } from "antd";

const UseScrollExample = () => {
  const ref = useRef(null);
  const scroll = useScroll(ref);

  return (
    <Card title="useScroll 滚动">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>滚动位置:</strong> {scroll?.top || 0}
        </p>
        <p>
          <strong>滚动方向:</strong> {scroll?.direction || "无"}
        </p>
      </div>

      <div
        ref={ref}
        style={{
          height: 200,
          overflow: "auto",
          border: "1px solid #d9d9d9",
          padding: 16,
        }}
      >
        {Array.from({ length: 20 }, (_, i) => (
          <div
            key={i}
            style={{ padding: 8, borderBottom: "1px solid #f0f0f0" }}
          >
            滚动内容 {i + 1}
          </div>
        ))}
      </div>
    </Card>
  );
};

useSize – 元素尺寸

useSize 用于监听元素尺寸变化。

import React, { useRef } from "react";
import { useSize } from "ahooks";
import { Card, Button } from "antd";

const UseSizeExample = () => {
  const ref = useRef(null);
  const size = useSize(ref);

  const toggleSize = () => {
    if (ref.current) {
      ref.current.style.width =
        ref.current.style.width === "200px" ? "300px" : "200px";
      ref.current.style.height =
        ref.current.style.height === "100px" ? "150px" : "100px";
    }
  };

  return (
    <Card title="useSize 元素尺寸">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>宽度:</strong> {size?.width}px
        </p>
        <p>
          <strong>高度:</strong> {size?.height}px
        </p>
      </div>

      <div
        ref={ref}
        style={{
          width: 200,
          height: 100,
          backgroundColor: "#f0f0f0",
          border: "1px solid #d9d9d9",
          borderRadius: 4,
          marginBottom: 16,
          transition: "all 0.3s",
        }}
      >
        监听尺寸的元素
      </div>

      <Button onClick={toggleSize}>切换尺寸</Button>
    </Card>
  );
};

useFocusWithin – 焦点状态

useFocusWithin 用于检测元素或其子元素是否获得焦点。

import React, { useRef } from "react";
import { useFocusWithin } from "ahooks";
import { Card, Input, Button, message } from "antd";

const UseFocusWithinExample = () => {
  const ref = useRef(null);
  const isFocusWithin = useFocusWithin(ref, {
    onFocus: () => {
      message.info("获得焦点");
    },
    onBlur: () => {
      message.info("失去焦点");
    },
  });

  return (
    <Card title="useFocusWithin 焦点状态">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>焦点状态:</strong> {JSON.stringify(isFocusWithin)}
        </p>
      </div>

      <div
        ref={ref}
        style={{
          padding: 16,
          backgroundColor: isFocusWithin ? "#f6ffed" : "#f0f0f0",
          border: "1px solid #d9d9d9",
          borderRadius: 4,
          transition: "background-color 0.3s",
        }}
      >
        <Input placeholder="点击我" style={{ marginBottom: 8 }} />
        <Button>按钮</Button>
      </div>
    </Card>
  );
};

DOM 类 hooks 速查表

Hook 名称用途描述
useEventListener事件监听器添加事件监听器
useClickAway点击外部检测点击元素外部的事件
useDocumentVisibility文档可见性监听文档可见性状态
useDrop & useDrag拖拽处理拖拽操作
useEventTarget事件目标处理表单输入事件
useExternal外部资源动态加载外部资源
useTitle页面标题动态设置页面标题
useFavicon网站图标动态设置网站图标
useFullscreen全屏控制全屏状态
useHover悬停状态检测元素悬停状态
useMutationObserver元素变化监听监听 DOM 元素变化
useInViewport视口可见性检测元素是否在视口中可见
useKeyPress键盘按键监听键盘按键事件
useLongPress长按检测长按事件
useMouse鼠标位置获取鼠标位置
useResponsive响应式检测屏幕尺寸
useScroll滚动监听滚动事件
useSize元素尺寸监听元素尺寸变化
useFocusWithin焦点状态检测元素或其子元素是否获得焦点
资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/789,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?