@ahmiao666/ahmiao-react-dialog-element
Version:
241 lines (186 loc) • 6.06 kB
Markdown
# 🎉 ahmiao React18 Dialog
高性能React18 Dialog组件,支持完整的性能控制和诊断功能。
## 🚀 安装
```bash
npm install @ahmiao666/ahmiao-react-dialog-element
```
## 📖 快速开始
```tsx
# amDialogCustom 弹窗组件使用说明 仅支持React18+ 因为底层订阅使用了 useSyncExternalStore
## 基本使用
### 使用之前需要先把提供者组件 DialogCustomProvider 挂在到 app 里
```tsx
// 在应用根组件中挂载一次
import { DialogCustomProvider } from '@ahmiao666/ahmiao-react-dialog-element'
import '@ahmiao666/ahmiao-react-dialog-element/index.css'
function AppRoot() {
return (
<>
{/* 你的 App */}
<DialogCustomProvider />
</>
)
}
```
```tsx
import { DialogCustomStaticMethods } from '@ahmiao666/ahmiao-react-dialog-element'
// 方式1: await 方式
const result = await DialogCustomStaticMethods.open(
({ onClose }) => (
<div>
<p>确定要删除吗?</p>
<button onClick={() => onClose(true)}>确定</button>
<button onClick={() => onClose(false)}>取消</button>
</div>
),
{
title: "确认删除",
width: 400
}
)
if (result) {
console.log('用户确认删除')
}
// 方式2: .then() 方式
DialogCustomStaticMethods.open(
({ onClose }) => (
<div>
<p>确定要删除吗?</p>
<button onClick={() => onClose(true)}>确定</button>
<button onClick={() => onClose(false)}>取消</button>
</div>
),
{
title: "确认删除",
width: 400
}
).then(result => {
if (result) {
console.log('用户确认删除')
}
}).catch(() => {
console.log('弹窗被取消')
})
```
## 配置选项
```tsx
DialogCustomStaticMethods.open(Component, {
title: '弹窗标题', // 标题文本
width: 500, // 宽度:number=vw,string=任意CSS宽度
showIcon: true, // 是否显示标题图标
showClose: true, // 是否显示关闭按钮
icon: '📣', // 自定义标题图标(可选)
maskClosable: true, // 点击遮罩是否可关闭
maskBg: 'rgba(0,0,0,0.6)', // 遮罩背景色(仅颜色)
familyName: 'settings', // 弹窗命名空间(用于多弹窗并存)
onNext: (v) => {}, // 可选的下一步回调(会传给内容组件)
props: { data: '数据' } // 传递给内容组件的自定义 props
})
```
### 遮罩与样式
- 仅支持通过 `maskBg` 修改遮罩颜色,默认值:`rgba(0, 0, 0, 0.4)`。
- 当同时打开多个弹窗时,遮罩只渲染一次,颜色取“最上层弹窗”的 `maskBg`。
```ts
DialogCustomStaticMethods.open(Comp, {
maskBg: 'rgba(0,0,0,0.6)'
})
```
## 多弹窗
```tsx
// 打开多个弹窗
DialogCustomStaticMethods.openWithFamily("settings", SettingsComponent)
DialogCustomStaticMethods.openWithFamily("profile", ProfileComponent)
// 或者通过 options.familyName 指定
DialogCustomStaticMethods.open(SettingsComponent, { familyName: 'settings' })
DialogCustomStaticMethods.open(ProfileComponent, { familyName: 'profile' })
// 关闭指定弹窗
DialogCustomStaticMethods.close("settings")
// 关闭所有弹窗
DialogCustomStaticMethods.closeAll()
```
## 回调方式
### 方式1: onClose回调
```tsx
const result = await DialogCustomStaticMethods.open(
({ onClose }) => (
<div>
<button onClick={() => onClose("保存")}>保存</button>
<button onClick={() => onClose(null)}>取消</button>
</div>
)
)
// result = "保存" 或 null
```
### 方式2: props回调
```tsx
const handleSave = (data) => console.log("保存:", data)
await DialogCustomStaticMethods.open(
({ onSave, onClose }) => (
<div>
<button onClick={() => onSave("数据")}>保存</button>
<button onClick={() => onClose()}>关闭</button>
</div>
),
{
props: { onSave: handleSave }
}
)
```
## 状态读取与订阅
> 这些 Hook/方法用于“读取弹窗状态”。推荐优先使用只读选择器,避免直接接触底层 Map。
### useHasOpenDialog
是否存在任意弹窗打开(订阅式)。
```tsx
import { useHasOpenDialog } from '@/am-ui/am-dialog'
export function Header() {
const hasOpen = useHasOpenDialog()
return hasOpen ? null : <TopBar />
}
```
### useFamilyVisible
指定 family 是否打开(订阅式)。
```tsx
import { useFamilyVisible } from '@/am-ui/am-dialog'
const profileOpen = useFamilyVisible('profile')
```
### useDialogSelector
通用选择器 Hook:订阅式返回派生值,避免暴露底层 Map。
```tsx
import { useDialogSelector } from '@/am-ui/am-dialog'
// 打开中的 family 列表
const openFamilies = useDialogSelector((states) =>
Array.from(states.entries())
.filter(([, s]) => s.visible)
.map(([family]) => family),
)
// 顶层弹窗标题(示例)
const topTitle = useDialogSelector((states) => {
const visible = Array.from(states.values()).filter((s) => s.visible && s.options)
const top = visible[visible.length - 1]
return top?.options?.title ?? ''
})
```
### getDialogFrozenSnapshot
一次性只读快照(非订阅)。适合在非 React 或初始化时读取。
```ts
import { getDialogFrozenSnapshot } from '@/am-ui/am-dialog'
const snap = getDialogFrozenSnapshot()
for (const [family, state] of snap) {
console.log(family, state.visible, state.options?.title)
}
```
### subscribeHasOpen
非 React 环境订阅“是否有弹窗打开”的变化(会立即回调一次当前值)。
```ts
import { subscribeHasOpen } from '@/am-ui/am-dialog'
const unsubscribe = subscribeHasOpen((hasOpen) => {
console.log('hasOpen changed:', hasOpen)
})
// 需要时机合适地取消订阅
unsubscribe()
```
> 写操作请始终使用现有 API:`DialogCustomStaticMethods.open/openWithFamily/close/closeAll` 或内容组件内的 `onClose`/`onNext`,不要直接修改底层 Map。
```
## 🔗 相关链接
- [完整文档](https://github.com/ahmiao666/ahmiao-react-dialog-element)
- [GitHub仓库](https://github.com/ahmiao666/ahmiao-react-dialog-element)