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 && (<divstyle={{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 – 拖拽
useDrop
和 useDrag
用于处理拖拽操作。
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 }}><divref={dragRef}draggableonDragStart={(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><divref={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 }}><Inputvalue={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 }}><divclassName="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><ButtononClick={() =>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 }}><Inputvalue={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><ButtononClick={() => 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><divref={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><divref={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><divref={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><divstyle={{ height: 200, overflow: "auto", border: "1px solid #d9d9d9" }}><div style={{ height: 100, backgroundColor: "#f0f0f0" }}>滚动区域顶部</div><divref={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><divref={ref}style={{height: 200,overflow: "auto",border: "1px solid #d9d9d9",padding: 16,}}>{Array.from({ length: 20 }, (_, i) => (<divkey={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><divref={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><divref={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 | 焦点状态 | 检测元素或其子元素是否获得焦点 |
React强大且灵活hooks库——ahooks入门实践之DOM类hook(dom)详解 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿动态资讯