NextJS开发:封装shadcn/ui中的AlertDialog确认对话框
shadcn/ui很灵活可以方便的自己修改class样式,但是仅仅一个确认删除弹窗,需要拷贝太多代码和导入太多包,重复的代码量太多,不利于代码维护。所以进一步封装以符合项目中使用。
封装cx-alert-dialog.tsx
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
import { CustomButton } from "./custom-button"
export const CxAlertDialog = (props: {
visible: boolean,
title?: string,
content?: string,
cancelText?: string,
okText?: string,
okColor?: string,
loading?: boolean,
disabled: boolean,
onClose: ()=>void,
onOk: ()=>void,
}) => {
const buildOkButton = () => {
if(props.okColor == "red") {
return (
<CustomButton variant="destructive" loading={props.loading} disabled={props.disabled} onClick={props.onOk}>{props.okText}</CustomButton>
)
}
else {
return (
<CustomButton loading={props.loading} disabled={props.disabled} onClick={props.onOk}>{props.okText}</CustomButton>
)
}
}
return (
<>
<AlertDialog open={props.visible}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{props.title}</AlertDialogTitle>
<AlertDialogDescription>
{props.content}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={props.onClose} disabled={props.disabled}>{props.cancelText}</AlertDialogCancel>
{ buildOkButton() }
{/* {
props.okColor == "red"
?
<AlertDialogAction className="bg-red-500 hover:bg-red-600" onClick={props.onOk}>{props.okText}</AlertDialogAction>
:
<AlertDialogAction onClick={props.onOk}>{props.okText}</AlertDialogAction>
} */}
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
)
}
custom-button.tsx
"use client"
import React, { MouseEventHandler } from "react";
import { Button } from "../ui/button";
import LcIcon from "./lc-icon";
import { cn } from "@/lib/utils";
/**
* Button扩展,增加图标功能
* <CustomButton icon="Loader" onClick={handleSubmit}>Button</CustomButton>
* */
export const CustomButton = (props: {
variant?: string,
size?: string,
className?: string,
iconClassName?: string,
icon?: string,
loading?: boolean
disabled?: boolean,
type?: string,
onClick?: MouseEventHandler<HTMLButtonElement>,
children?: any
}) => {
const buildIcon = () => {
if(props.loading != null && props.loading) {
return <LcIcon name="Loader" size={16} className={cn("animate-spin", props.iconClassName ?? 'mr-1' )}/>
}
else if(props.icon != null) {
return <LcIcon name={props.icon} size={16} className={props.iconClassName ?? 'mr-1'}/>
}
return ""
}
return (
<Button size={props.size as any ?? "default"} variant={props.variant as any ?? "default"} type={props.type ?? 'button' as any} className={props.className} disabled={props.disabled} onClick={props.onClick}>
{ buildIcon() }
{ props.children }
</Button>
)
}
使用CxAlertDialog组件
const [delAlertVisible, setDelAlertVisible]:[boolean, Dispatch<SetStateAction<boolean>>] = React.useState(false);
const [delAlertLoading, setDelAlertLoading]:[boolean, Dispatch<SetStateAction<boolean>>] = React.useState(false);
const currOperId = useRef(BigInt(0))
const handleDelAlertOk = async () => {
setDelAlertLoading(true)
await ChapterApi.del(Number(props.docId), currOperId.current).catch((e) => ErrUtils.apiHandle(e)).then((resp)=>{
//console.log(resp)
if(!resp) return
if(resp?.code == RespCode.Success) {
setDelAlertVisible(false)
ToastUtils.success({ msg: resp?.msg })
currChapterId.current = ""
refresh()
} else {
ToastUtils.error({ msg: resp?.msg ?? "22" })
}
})
.finally(()=>{
setDelAlertLoading(false)
})
}
const buildDel = () => {
return (
<CxAlertDialog visible={delAlertVisible} okColor="red" title="提示" content="确认删除?" cancelText="取消" okText="删除"
onClose={() => setDelAlertVisible(false)} onOk={() => handleDelAlertOk()} loading={delAlertLoading} disabled={delAlertLoading}/>
)
}