component-library-for-react
v1.2.1
Published
这是一个关于react的组件库
Readme
项目全量使用文档
📦 包含的 PACKAGES
⚓ 包含的 HOOKS
🛠️ 包含的 TOOLS
useBodyScrollLock
useBodyScrollLock 使用文档
useBodyScrollLock 是一个用于锁定页面滚动的自定义 Hook。
当传入参数为 true 时,会禁止页面滚动;当参数变为 false 或组件卸载时,会自动恢复页面滚动状态。
支持多个组件同时使用滚动锁,只有最后一个滚动锁释放后才会恢复页面滚动。
1. API 参数说明
入参(Inputs)
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
| :--------- | :-------- | :--- | :------ | :--------------- |
| isLocked | boolean | 否 | false | 是否锁定页面滚动 |
出参(Outputs)
- void
该 Hook 无返回值。
2. 基础用法(Modal 弹窗)
import { FC, useState } from "react";
import { css } from "@emotion/react";
import { useBodyScrollLock } from "component-library-for-react";
const style = css`
height: 200vh;
`;
const maskStyle = css`
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.3);
`;
const App: FC = () => {
const [isLocked, setIsLocked] = useState(false);
useBodyScrollLock(isLocked);
const changeStatus = () => {
setIsLocked((prev) => !prev);
};
return (
<div css={style}>
<button onClick={changeStatus}>切换滚动锁</button>
{isLocked && <div css={maskStyle} onClick={changeStatus} />}
</div>
);
};
export default App;3. 使用效果
允许滚动
useBodyScrollLock(false);页面可以正常滚动。
禁止滚动
useBodyScrollLock(true);页面滚动被锁定。
内部会自动设置:
body {
overflow: hidden;
}如果页面存在滚动条,还会自动补偿滚动条宽度,避免布局抖动。
4. 多弹窗场景
多个组件可以同时使用:
useBodyScrollLock(isModalOpen);
useBodyScrollLock(isDrawerOpen);执行过程:
Modal 打开
↓
Drawer 打开
↓
Modal 关闭
↓
Drawer 关闭只有 Drawer 关闭后,页面滚动才会恢复。
无需业务侧自行维护锁计数。
5. 注意事项
建议使用布尔值控制
推荐:
useBodyScrollLock(isOpen);不推荐:
useBodyScrollLock(data.length > 0);应保证参数语义明确。
不要手动修改 Body 样式
Hook 会自动管理:
body {
overflow
padding-right
}业务代码不建议同时修改这两个属性,以避免样式冲突。
6. 适用场景
- Modal
- Drawer
- 图片预览
- 全屏遮罩
- Loading 页面
- 多层嵌套弹窗
- 移动端菜单展开
当需要用户聚焦当前内容并阻止背景页面滚动时,可以使用该 Hook。
useClickOutside
useClickOutside 使用文档
useClickOutside 是一个用于监听目标元素外部点击事件的自定义 Hook。当用户点击了指定 DOM 元素之外的区域时,会触发传入的回调函数。可用于下拉菜单等组件的收起逻辑。
1. API 参数说明
入参 (Inputs)
| 参数名 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| ref | RefObject<HTMLElement \| null> | 是 | 由 useRef 创建的引用对象,需绑定到目标 DOM 元素上 |
| handler | (event: MouseEvent \| TouchEvent) => void | 是 | 点击目标元素外部时触发的回调函数 |
出参 (Outputs)
void: 该 Hook 无返回值。
2. 基础用法(下拉菜单)
点击按钮打开菜单,点击菜单外部的任意地方自动关闭菜单。
import React, { FC, useState, useRef, useCallback } from "react";
import { css } from "@emotion/react";
import { useClickOutside } from 'component-library-for-react'
const App: FC = () => {
const [isOpen, setIsOpen] = useState(false);
const [list] = useState([
{ text: '菜单001', key: '001' },
{ text: '菜单002', key: '002' }
]);
const ref = useRef<HTMLUListElement | null>(null);
const changeIsOpenState = (e: React.MouseEvent<HTMLButtonElement>) => {
setIsOpen(!isOpen);
e.stopPropagation();
}
const handler = useCallback(() => {
setIsOpen(false);
}, []);
useClickOutside(ref, handler);
const listStyle = css`
list-style: none;
li {
color: #333;
&:hover {
color: red;
cursor: pointer;
}
}
`;
return (
<div>
<button onClick={e => changeIsOpenState(e)}>
{isOpen ? '关闭' : '打开'}菜单
</button>
{isOpen && (
<ul css={listStyle} ref={ref}>
{list.map(item => (
<li key={item.key}>{item.text}</li>
))}
</ul>
)}
</div>
);
};
export default App;useDebounce
useDebounce 使用文档
useDebounce 是一个用于处理函数防抖的自定义 Hook。它支持延迟执行和立即执行两种模式,并支持手动取消。
1. API 参数说明
入参 (Inputs)
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
| :---------- | :--------- | :--- | :------ | :------------------------- |
| fn | Function | 是 | - | 需要进行防抖处理的目标函数 |
| delay | number | 否 | 300 | 防抖延迟时间(毫秒) |
| immediate | boolean | 否 | false | 是否在第一次触发时立即执行 |
出参 (Outputs)
返回一个对象,包含以下两个方法:
run:(...args) => void—— 实际在业务中调用的防抖包装函数。参数与原函数fn保持一致。cancel:() => void—— 手动取消当前未执行的定时器。
2. 基础用法(搜索框输入)
连续输入时不会触发change事件,停止输入 2000ms 后才触发。
import { FC, useEffect } from "react";
import { useDebounce } from "component-library-for-react";
const App: FC = () => {
const logValue = (label:string,value:string)=>{
console.log(`当前输入的${label} 是 ${value}`)
}
const { run: runUsername, cancel: cancelUsername } = useDebounce(
(val: string) => logValue('username', val),
2000
);
const { run: runPassword, cancel: cancelPassword } = useDebounce(
(val: string) => logValue('password', val),
2000
);
useEffect(() => {
return () => {
cancelUsername();
cancelPassword();
};
}, [cancelUsername, cancelPassword]);
return <div>
<form encType="application/x-www-form-urlencoded">
<label htmlFor="username">
用户名:
<input type="text" name="username" onChange={e=>runUsername(e.target.value)}/>
</label>
<label htmlFor="password">
密 码:
<input type="password" name="password" onChange={e=>runPassword(e.target.value)}/>
</label>
<button type="button">提交</button>
</form>
</div>
};
export default App;useInfiniteScroll
useInfiniteScroll 使用文档
useInfiniteScroll 是一个无限滚动加载 Hook。
当用户滚动到列表底部时,会自动触发数据加载。
适用于:
- 商品列表
- 评论列表
- 消息记录
- 瀑布流
1. API参数说明
入参(Inputs)
| 参数名 | 类型 | 必填 | 说明 | | ------------ | ------------------------------ | ---- | ------------------ | | containerRef | RefObject<HTMLElement | null> | 是 | 滚动容器引用 | | loadMore | () => Promise | 是 | 加载更多数据的方法 | | options | FunctionOptionsType | 是 | 配置项 |
options配置
| 参数 | 类型 | 默认值 | 说明 | | ----------- | ------- | ------ | -------------------------- | | threshold | number | 100 | 距离底部多少像素时开始加载 | | isHasMore | boolean | false | 是否还有更多数据 | | isImmediate | boolean | true | 是否自动加载第一页 |
返回值(Outputs)
| 名称 | 类型 | 说明 | | ----------- | -------------- | ---------------- | | isLoading | boolean | 当前是否正在加载 | | sentinelRef | (node) => void | 观察哨元素Ref | | reset | () => void | 重置加载状态 |
2. 基础用法
const containerRef = useRef<HTMLDivElement>(null);
const { isLoading, sentinelRef } = useInfiniteScroll(containerRef, loadMore, {
isHasMore,
threshold: 20,
});3. 完整示例
import { useRef, useState } from "react";
import { useInfiniteScroll } from "component-library-for-react";
const App = () => {
const containerRef = useRef<HTMLDivElement>(null);
const [list, setList] = useState<number[]>([]);
const [isHasMore, setIsHasMore] = useState(true);
const loadMore = async () => {
await new Promise((resolve) => setTimeout(resolve, 500));
setList((prev) => {
const next = [...prev, ...Array.from({ length: 10 }, (_, i) => prev.length + i)];
if (next.length >= 50) {
setIsHasMore(false);
}
return next;
});
};
const { isLoading, sentinelRef } = useInfiniteScroll(containerRef, loadMore, {
isHasMore,
threshold: 20,
});
return (
<div
ref={containerRef}
style={{
height: "400px",
overflowY: "auto",
}}
>
{list.map((item) => (
<div key={item}>{item}</div>
))}
{isHasMore && <div ref={sentinelRef}>{isLoading ? "加载中..." : "继续下滑加载"}</div>}
</div>
);
};
export default App;4. 手动控制第一页加载
默认:
isImmediate: true;自动加载第一页。
如果希望手动加载:
useInfiniteScroll(containerRef, loadMore, {
isHasMore,
isImmediate: false,
});然后:
loadMore();自行触发。
5. 提前预加载
threshold: 200;表示:
距离底部200px
提前触发加载适用于:
- 图片列表
- 商品列表
- 请求耗时较长场景
6. 加载完成
当:
isHasMore = false;时:
停止触发加载例如:
if (total >= 100) {
setIsHasMore(false);
}7. 常见使用场景
商品列表
商品分页加载;评论区
评论分页加载;聊天记录
历史消息加载;瀑布流
图片无限滚动;用户列表
用户分页查询;useStorage
useStorage 使用文档
useStorage 是一个用于管理 localStorage 的自定义 Hook。它将 React State 与 localStorage 自动同步,使数据在页面刷新后依然能够保留。
1. API 参数说明
入参 (Inputs)
| 参数名 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| key | string | 是 | localStorage 存储键名 |
| initValue | T | 是 | 默认值,当缓存不存在时使用 |
出参 (Outputs)
| 名称 | 类型 | 说明 |
| :--- | :--- | :--- |
| value | T | 当前缓存值 |
| setValue | Dispatch<SetStateAction<T>> | 更新缓存值的方法 |
2. 基础用法(用户信息缓存)
import { FC } from "react";
import { useStorage } from "component-library-for-react";
const App: FC = () => {
const [storage, setStorage] = useStorage(
"user",
{
username: "张三"
}
);
return (
<div>
<p>用户名称:{storage.username}</p>
<button
onClick={() => {
setStorage({
username: "李四"
});
}}
>
修改名称
</button>
</div>
);
};
export default App;刷新页面后,用户名称依然会保留在 localStorage 中。
3. 函数式更新
与 React 的 useState 完全一致。
setStorage(prev => ({
...prev,
age: 19
}));完整示例:
import { FC } from "react";
import { useStorage } from "component-library-for-react";
const App: FC = () => {
const [storage, setStorage] = useStorage(
"user",
{
username: "张三"
}
);
return (
<div>
<p>用户名:{storage.username}</p>
<p>年龄:{storage.age}</p>
<button
onClick={() => {
setStorage(prev => ({
...prev,
age: 19
}));
}}
>
设置年龄
</button>
</div>
);
};
export default App;3. 使用场景
适用于:
- 登录用户信息缓存
- Token 持久化
- 页面主题切换
- 表单草稿保存
- 搜索历史记录
- 用户偏好设置
例如:
const [theme, setTheme] = useStorage(
"theme",
"light"
);刷新页面后依然保留用户选择的主题配置。
useThrottle
useThrottle 使用文档
useThrottle 是一个用于函数节流(Throttle)的自定义 Hook。它可以将连续的高频操作限制为每隔固定时间仅执行一次。
1. API 参数说明
入参 (Inputs)
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- | :--- |
| fn | Function | 是 | - | 需要限制执行频率的目标业务函数 |
| delay | number | 否 | 300 | 节流的时间间隔(毫秒) |
| immediate | boolean | 否 | false | 是否在第一次触发时立即执行。设为 false 则首下会延迟 delay 毫秒后执行 |
出参 (Outputs)
返回一个包含控制方法的对象:
run:(...args) => void—— 经过节流包装后的触发函数,参数类型与原函数严格一致。cancel:() => void—— 清除当前正在排队的定时器,并重置时间戳计数。
2. 基础用法:(表单提交)
由于 immediate 默认为 false,在连续点击提交的按钮时,每隔2s执行一次。
import React ,{ FC, useEffect, useRef } from "react";
import { useThrottle } from "component-library-for-react";
const App: FC = () => {
const formRef = useRef<HTMLFormElement|null>(null);
const submitFormData = (e:React.MouseEvent<HTMLButtonElement>)=>{
const formData = new FormData(formRef.current!);
console.log(formData.get('username'))
}
const {run,cancel} = useThrottle(submitFormData,2000);
useEffect(()=>{
return ()=>cancel()
},[cancel])
return <div>
<form ref={formRef} encType="application/x-www-form-urlencoded">
<label htmlFor="username">
用户名:
<input type="text" name="username"/>
</label>
<label htmlFor="password">
密 码:
<input type="password" name="password"/>
</label>
<button type="button" onClick={run}>提交</button>
</form>
</div>
};
export default App;LazyLoadImage
LazyLoadImage 使用文档
LazyLoadImage 是一个支持图片懒加载和渐显动画效果的 React 组件。
导入组件
import {LazyLoadImage} from "component-library-for-react";属性 API (Props)
| 属性名 | 类型 | 必填 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- | :--- |
| src | string | 是 | - | 真实图片的 URL 地址 |
| placeholder | string | 是 | - | 占位图或 Base64 低清图的 URL 地址 |
| alt | string | 否 | - | 图片的替代文本 |
| className | string | 否 | "" | 额外的 CSS 类名 |
| style | CSSProperties | 否 | {} | 覆盖或新增的内联样式 |
使用示例
1. 自定义样式与尺寸
组件默认宽度为 200px。你可以通过 style 或 className 自定义宽高。
<LazyLoadImage
src="http://adolphjie.com/xxx.png"
placeholder="/assets/default-avatar.png"
style={{ width: "100px", height: "100px", borderRadius: "50%" }}
/>PreviewImage
PreviewImage 使用文档
PreviewImage 是一个全屏图片预览组件。
支持:
- 单图预览
- 多图轮播
- 放大缩小
- 图片旋转
- 文件名展示
- 本地文件预览
- 网络图片预览
1. API 参数说明
入参(Props)
| 参数名 | 类型 | 必填 | 说明 | | :------- | :---------- | :--- | :--------------- | | fileList | FileProps[] | 是 | 图片列表 | | onClose | () => void | 否 | 点击关闭按钮触发 |
FileProps
interface FileProps {
file: File | Blob | string;
filename?: string;
}2. 基础用法(网络图片)
import { useState } from "react";
import {PreviewImage} from "component-library-for-react";
export default function App() {
const [open, setOpen] = useState(true);
return (
<>
{open && (
<PreviewImage
fileList={[
{
file: "https://picsum.photos/800/500",
filename: "demo.jpg",
},
]}
onClose={() => setOpen(false)}
/>
)}
</>
);
}3. 多图预览
<PreviewImage
fileList={[
{
file: image1,
filename: "001.png",
},
{
file: image2,
filename: "002.png",
},
{
file: image3,
filename: "003.png",
},
]}
/>组件会自动显示:
001.png (1 / 3)并支持左右切换。
4. 本地文件预览
const file = e.target.files?.[0];
<PreviewImage
fileList={[
{
file,
filename: file.name,
},
]}
/>;支持:
- jpg
- jpeg
- png
- webp
- gif
等浏览器可识别图片格式。
5. 内置操作功能
图片放大
点击:
+每次增加:
0.2倍最大:
3倍图片缩小
点击:
-每次减少:
0.2倍最小:
0.3倍图片旋转
支持:
逆时针旋转90°
顺时针旋转90°图片切换
多图情况下:
上一张
下一张循环切换。
关闭预览
点击右上角关闭按钮:
×触发:
onClose?.();6. 注意事项
fileList不能为空
推荐:
{
visible && <PreviewImage fileList={fileList} />;
}组件内部会在空数组时返回:
null;建议受控使用
推荐:
const [open, setOpen] = useState(false);通过状态控制组件显示与隐藏。
7. 适用场景
- 图片上传预览
- IM 图片查看
- 电商商品预览
- 文件管理系统
- 图片资源库
- 后台管理系统附件查看
Teleport
Teleport 使用文档
Teleport 是一个基于 React Portal 封装的组件,用于将子节点渲染到指定 DOM 节点下,而不是当前组件所在的 DOM 层级。
常用于:
- Modal 弹窗
- Drawer 抽屉
- Message 提示
- Notification 通知
- Tooltip 提示框
- 图片预览组件
通过 Teleport 可以避免受到父级容器的:
- overflow
- z-index
- transform
- position
等样式影响。
1. API 参数说明
Props
| 参数名 | 类型 | 必填 | 说明 |
| :--------- | :---------- | :--- | :----------------- |
| to | string | 是 | 目标挂载节点选择器 |
| children | ReactNode | 是 | 需要渲染的内容 |
2. 基础用法
将内容渲染到 body 节点。
import {Teleport} from "component-library-for-react";
function App() {
return (
<Teleport to="body">
<div>我是渲染到 body 的内容</div>
</Teleport>
);
}实际 DOM:
<body>
<div>我是渲染到 body 的内容</div>
</body>3. 挂载到指定节点
HTML:
<div id="root"></div>
<div id="modal-root"></div>React:
<Teleport to="#modal-root">
<div>Modal 内容</div>
</Teleport>渲染结果:
<div id="modal-root">
<div>Modal 内容</div>
</div>4. Modal 示例
import { useState } from "react";
import Teleport from "./Teleport";
function App() {
const [visible, setVisible] = useState(false);
return (
<>
<button onClick={() => setVisible(true)}>打开弹窗</button>
{visible && (
<Teleport to="body">
<div
style={{
position: "fixed",
inset: 0,
background: "rgba(0,0,0,.5)",
}}
onClick={() => setVisible(false)}
>
Modal内容
</div>
</Teleport>
)}
</>
);
}5. 注意事项
目标节点必须存在
推荐:
<Teleport to="#modal-root">
<Modal />
</Teleport>并确保页面存在:
<div id="modal-root"></div>否则组件不会渲染任何内容。
支持任意合法选择器
例如:
<Teleport to="body" />
<Teleport to="#app" />
<Teleport to=".container" />内部通过:
document.querySelector();查找目标节点。
首次渲染为空
组件会在:
useEffect();执行后获取目标节点。
因此首次渲染时:
return null;属于正常现象。
6. 适用场景
- Modal
- Drawer
- Message
- Notification
- Tooltip
- 图片预览器
- 全局浮层组件
凡是需要脱离当前 DOM 层级渲染的场景均可使用。
Upload
Upload 使用文档
LazyLoadImage 是一个基于 React的轻量级文件上传组件,支持类型限制、多选以及最大数量截断。
导入组件
import {Upload} from "component-library-for-react";属性 API (Props)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- | :--- |
| action | string | 是 | - | 上传的后端接口 URL 地址 |
| accept | string | 否 | - | 限制可选的文件类型,如 image/* 或 .pdf,.docx |
| multiple | boolean | 否 | false | 是否支持按住 Ctrl/Shift 选择多个文件 |
| maxCount | number | 否 | - | 允许上传的最大文件数量限制 |
| onChange | (files: File[]) => void | 否 | - | 文件列表发生变化(添加/删除/截断)时的回调函数 |
基础使用示例
1. 单张图片上传
import Upload from './Upload';
const APP = ()=>{
const params = {
action:"http://127.0.0.1:4000/file",
}
return <div>
<Upload {...params}/>
</div>
}
export default APP;2. 多文档限制上传(最多3个)
import Upload from './Upload';
const params = {
action:"http://127.0.0.1:4000/files",
multiple:true,
accept:".pdf,.doc,.docx",
maxCount:3,
onChange:(files:File[]) => console.log('最新的文档列表:', files)
}
const APP = ()=>{
return <div>
<Upload {...params}/>
</div>
}
export default APP;后端接收注意事项
- 单文件模式 (
multiple={false}):后端需通过名为file的字段获取单个文件。 - 多文件模式 (
multiple={true}):后端需通过名为files的字段获取文件数组(例如 Node.js 中使用upload.array('files'))。
VirtualList
VirtualList 使用文档
VirtualList 是一个专为 React 打造的高性能、轻量级固定高度虚拟列表组件。当你的业务场景需要承载几千甚至数万条结构相同的列表数据时,该组件能将 DOM 节点数控制在极低的个位数,确保页面维持 60 FPS 的流畅度。
导入组件
import {VirtualList} from "component-library-for-react";属性 API (Props)
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
| :--- | :--- | :---: | :---: | :--- |
| listData | T[] | 是 | - | 列表的数据源数组(任意类型对象的数组)。 |
| itemHeight | number | 是 | - | 单行数据的绝对高度(单位 px),行内内容必须严丝合缝匹配此高度。 |
| height | number | 是 | - | 可视区域的容器高度(单位 px)。超出该高度将自动出现滚动条。 |
| renderItem | (item: T, index: number) => ReactNode | 是 | - | 单行自定义渲染函数。接收单条数据 item 及全局真实索引 index。 |
使用示例
import { FC,useState } from "react";
import {VirtualList} from "./packages/index"
const APP:FC = ()=>{
const [list] = useState<Array<string>>([
"内容...1",
"内容...2",
"内容...3",
"内容...4",
"内容...5",
"内容...6",
"内容...7",
"内容...1",
"内容...2",
"内容...3",
"内容...4",
"内容...5",
"内容...6",
"内容...7",
]);
const props = {
listData:list,
itemHeight:30,
height:100,
renderItem:(item:string,index:number)=>{
return <div key={index}>{item}</div>
}
}
return <div>
<VirtualList {...props}></VirtualList>
</div>
}
export default APP;storage
storage 使用文档
storage 是一个浏览器缓存工具,用于快速操作:
- localStorage
- sessionStorage
支持:
- 自动 JSON 序列化
- 自动 JSON 反序列化
- TypeScript 泛型推导
1. 导入
import { storage } from "component-library-for-react";
const { localStore, sessionStore } = storage;2. API说明
set
写入缓存
set(
key: string,
value: unknown
): voidget
获取缓存
get<T = unknown>(
key: string
): T | string | nulldelete
删除指定缓存
delete(
key: string
): voidclear
清空全部缓存
clear(): void3. localStorage 示例
存储字符串
localStore.set("token", "abcdefg");读取:
const token = localStore.get("token");结果:
abcdefg4. 使用场景
适用于:
- Token缓存
- 用户信息缓存
- 页面主题存储
- 搜索历史记录
- 表单草稿保存
- 多页面共享数据
推荐:
localStore;用于长期存储。
sessionStore;用于会话级存储。
