mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-08 01:17:23 +08:00
feat: 新增函数式弹框组件,使用更便捷
This commit is contained in:
parent
4ae0d9bc04
commit
3705a0c11b
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-config-provider :locale="currentLocale">
|
<el-config-provider :locale="currentLocale">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
<ReDialog />
|
||||||
</el-config-provider>
|
</el-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -9,10 +10,12 @@ import { defineComponent } from "vue";
|
|||||||
import { ElConfigProvider } from "element-plus";
|
import { ElConfigProvider } from "element-plus";
|
||||||
import zhCn from "element-plus/lib/locale/lang/zh-cn";
|
import zhCn from "element-plus/lib/locale/lang/zh-cn";
|
||||||
import en from "element-plus/lib/locale/lang/en";
|
import en from "element-plus/lib/locale/lang/en";
|
||||||
|
import { ReDialog } from "@/components/ReDialog";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "app",
|
name: "app",
|
||||||
components: {
|
components: {
|
||||||
[ElConfigProvider.name]: ElConfigProvider
|
[ElConfigProvider.name]: ElConfigProvider,
|
||||||
|
ReDialog
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentLocale() {
|
currentLocale() {
|
||||||
|
39
src/components/ReDialog/index.ts
Normal file
39
src/components/ReDialog/index.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { ref } from "vue";
|
||||||
|
import reDialog from "./index.vue";
|
||||||
|
import { useTimeoutFn } from "@vueuse/core";
|
||||||
|
import { withInstall } from "@pureadmin/utils";
|
||||||
|
import type {
|
||||||
|
EventType,
|
||||||
|
ArgsType,
|
||||||
|
DialogProps,
|
||||||
|
ButtonProps,
|
||||||
|
DialogOptions
|
||||||
|
} from "./type";
|
||||||
|
|
||||||
|
const dialogStore = ref<Array<DialogOptions>>([]);
|
||||||
|
|
||||||
|
const addDialog = (options: DialogOptions) => {
|
||||||
|
const open = () =>
|
||||||
|
dialogStore.value.push(Object.assign(options, { visible: true }));
|
||||||
|
if (options?.openDelay) {
|
||||||
|
useTimeoutFn(() => {
|
||||||
|
open();
|
||||||
|
}, options.openDelay);
|
||||||
|
} else {
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDialog = (options: DialogOptions, index: number, args: any) => {
|
||||||
|
dialogStore.value.splice(index, 1);
|
||||||
|
options.closeCallBack && options.closeCallBack(args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeAllDialog = () => {
|
||||||
|
dialogStore.value = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const ReDialog = withInstall(reDialog);
|
||||||
|
|
||||||
|
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };
|
||||||
|
export { ReDialog, dialogStore, addDialog, closeDialog, closeAllDialog };
|
106
src/components/ReDialog/index.vue
Normal file
106
src/components/ReDialog/index.vue
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { isFunction } from "@pureadmin/utils";
|
||||||
|
import {
|
||||||
|
type DialogOptions,
|
||||||
|
type ButtonProps,
|
||||||
|
type EventType,
|
||||||
|
dialogStore,
|
||||||
|
closeDialog
|
||||||
|
} from "./index";
|
||||||
|
|
||||||
|
const footerButtons = computed(() => {
|
||||||
|
return (options: DialogOptions) => {
|
||||||
|
return options?.footerButtons?.length > 0
|
||||||
|
? options.footerButtons
|
||||||
|
: ([
|
||||||
|
{
|
||||||
|
label: "取消",
|
||||||
|
text: true,
|
||||||
|
bg: true,
|
||||||
|
btnClick: ({ dialog: { options, index } }) => {
|
||||||
|
closeDialog(options, index, { command: "cancel" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "确定",
|
||||||
|
type: "primary",
|
||||||
|
text: true,
|
||||||
|
bg: true,
|
||||||
|
btnClick: ({ dialog: { options, index } }) => {
|
||||||
|
closeDialog(options, index, { command: "sure" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as Array<ButtonProps>);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function eventsCallBack(
|
||||||
|
event: EventType,
|
||||||
|
options: DialogOptions,
|
||||||
|
index: number
|
||||||
|
) {
|
||||||
|
if (options?.[event] && isFunction(options?.[event])) {
|
||||||
|
return options?.[event]({ options, index });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClose(
|
||||||
|
options: DialogOptions,
|
||||||
|
index: number,
|
||||||
|
args = { command: "close" }
|
||||||
|
) {
|
||||||
|
closeDialog(options, index, args);
|
||||||
|
eventsCallBack("close", options, index);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-for="(options, index) in dialogStore"
|
||||||
|
:key="index"
|
||||||
|
v-bind="options"
|
||||||
|
v-model="options.visible"
|
||||||
|
@opened="eventsCallBack('open', options, index)"
|
||||||
|
@close="handleClose(options, index)"
|
||||||
|
@openAutoFocus="eventsCallBack('openAutoFocus', options, index)"
|
||||||
|
@closeAutoFocus="eventsCallBack('closeAutoFocus', options, index)"
|
||||||
|
>
|
||||||
|
<!-- header -->
|
||||||
|
<template
|
||||||
|
v-if="options?.headerRenderer"
|
||||||
|
#header="{ close, titleId, titleClass }"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="options?.headerRenderer({ close, titleId, titleClass })"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<!-- default -->
|
||||||
|
<component
|
||||||
|
v-bind="options?.props"
|
||||||
|
:is="options.contentRenderer({ options, index })"
|
||||||
|
@close="args => handleClose(options, index, args)"
|
||||||
|
/>
|
||||||
|
<!-- footer -->
|
||||||
|
<template v-if="!options?.hideFooter" #footer>
|
||||||
|
<template v-if="options?.footerRenderer">
|
||||||
|
<component :is="options?.footerRenderer({ options, index })" />
|
||||||
|
</template>
|
||||||
|
<span v-else>
|
||||||
|
<el-button
|
||||||
|
v-for="(btn, key) in footerButtons(options)"
|
||||||
|
:key="key"
|
||||||
|
v-bind="btn"
|
||||||
|
@click="
|
||||||
|
btn.btnClick({
|
||||||
|
dialog: { options, index },
|
||||||
|
button: { btn, index: key }
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ btn?.label }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
186
src/components/ReDialog/type.ts
Normal file
186
src/components/ReDialog/type.ts
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import type { CSSProperties, VNode, Component } from "vue";
|
||||||
|
|
||||||
|
type DoneFn = (cancel?: boolean) => void;
|
||||||
|
type EventType = "open" | "close" | "openAutoFocus" | "closeAutoFocus";
|
||||||
|
type ArgsType = {
|
||||||
|
/** `cancel` 点击取消按钮、`sure` 点击确定按钮、`close` 点击右上角关闭按钮或者空白页 */
|
||||||
|
command: "cancel" | "sure" | "close";
|
||||||
|
};
|
||||||
|
|
||||||
|
/** https://element-plus.org/zh-CN/component/dialog.html#attributes */
|
||||||
|
type DialogProps = {
|
||||||
|
/** `Dialog` 的显示与隐藏 */
|
||||||
|
visible?: boolean;
|
||||||
|
/** `Dialog` 的标题 */
|
||||||
|
title?: string;
|
||||||
|
/** `Dialog` 的宽度,默认 `50%` */
|
||||||
|
width?: string | number;
|
||||||
|
/** 是否为全屏 `Dialog`,默认 `false` */
|
||||||
|
fullscreen?: boolean;
|
||||||
|
/** `Dialog CSS` 中的 `margin-top` 值,默认 `15vh` */
|
||||||
|
top?: string;
|
||||||
|
/** 是否需要遮罩层,默认 `true` */
|
||||||
|
modal?: boolean;
|
||||||
|
/** `Dialog` 自身是否插入至 `body` 元素上。嵌套的 `Dialog` 必须指定该属性并赋值为 `true`,默认 `false` */
|
||||||
|
appendToBody?: boolean;
|
||||||
|
/** 是否在 `Dialog` 出现时将 `body` 滚动锁定,默认 `true` */
|
||||||
|
lockScroll?: boolean;
|
||||||
|
/** `Dialog` 的自定义类名 */
|
||||||
|
class?: string;
|
||||||
|
/** `Dialog` 的自定义样式 */
|
||||||
|
style?: CSSProperties;
|
||||||
|
/** `Dialog` 打开的延时时间,单位毫秒,默认 `0` */
|
||||||
|
openDelay?: number;
|
||||||
|
/** `Dialog` 关闭的延时时间,单位毫秒,默认 `0` */
|
||||||
|
closeDelay?: number;
|
||||||
|
/** 是否可以通过点击 `modal` 关闭 `Dialog`,默认 `true` */
|
||||||
|
closeOnClickModal?: boolean;
|
||||||
|
/** 是否可以通过按下 `ESC` 关闭 `Dialog`,默认 `true` */
|
||||||
|
closeOnPressEscape?: boolean;
|
||||||
|
/** 是否显示关闭按钮,默认 `true` */
|
||||||
|
showClose?: boolean;
|
||||||
|
/** 关闭前的回调,会暂停 `Dialog` 的关闭. 回调函数内执行 `done` 参数方法的时候才是真正关闭对话框的时候 */
|
||||||
|
beforeClose?: (done: DoneFn) => void;
|
||||||
|
/** 为 `Dialog` 启用可拖拽功能,默认 `false` */
|
||||||
|
draggable?: boolean;
|
||||||
|
/** 是否让 `Dialog` 的 `header` 和 `footer` 部分居中排列,默认 `false` */
|
||||||
|
center?: boolean;
|
||||||
|
/** 是否水平垂直对齐对话框,默认 `false` */
|
||||||
|
alignCenter?: boolean;
|
||||||
|
/** 当关闭 `Dialog` 时,销毁其中的元素,默认 `false` */
|
||||||
|
destroyOnClose?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type BtnClickDialog = {
|
||||||
|
options?: DialogOptions;
|
||||||
|
index?: number;
|
||||||
|
};
|
||||||
|
type BtnClickButton = {
|
||||||
|
btn?: ButtonProps;
|
||||||
|
index?: number;
|
||||||
|
};
|
||||||
|
/** https://element-plus.org/zh-CN/component/button.html#button-attributes */
|
||||||
|
type ButtonProps = {
|
||||||
|
/** 按钮文字 */
|
||||||
|
label: string;
|
||||||
|
/** 按钮尺寸 */
|
||||||
|
size?: "large" | "default" | "small";
|
||||||
|
/** 按钮类型 */
|
||||||
|
type?: "primary" | "success" | "warning" | "danger" | "info";
|
||||||
|
/** 是否为朴素按钮,默认 `false` */
|
||||||
|
plain?: boolean;
|
||||||
|
/** 是否为文字按钮,默认 `false` */
|
||||||
|
text?: boolean;
|
||||||
|
/** 是否显示文字按钮背景颜色,默认 `false` */
|
||||||
|
bg?: boolean;
|
||||||
|
/** 是否为链接按钮,默认 `false` */
|
||||||
|
link?: boolean;
|
||||||
|
/** 是否为圆角按钮,默认 `false` */
|
||||||
|
round?: boolean;
|
||||||
|
/** 是否为圆形按钮,默认 `false` */
|
||||||
|
circle?: boolean;
|
||||||
|
/** 是否为加载中状态,默认 `false` */
|
||||||
|
loading?: boolean;
|
||||||
|
/** 自定义加载中状态图标组件 */
|
||||||
|
loadingIcon?: string | Component;
|
||||||
|
/** 按钮是否为禁用状态,默认 `false` */
|
||||||
|
disabled?: boolean;
|
||||||
|
/** 图标组件 */
|
||||||
|
icon?: string | Component;
|
||||||
|
/** 是否开启原生 `autofocus` 属性,默认 `false` */
|
||||||
|
autofocus?: boolean;
|
||||||
|
/** 原生 `type` 属性,默认 `button` */
|
||||||
|
nativeType?: "button" | "submit" | "reset";
|
||||||
|
/** 自动在两个中文字符之间插入空格 */
|
||||||
|
autoInsertSpace?: boolean;
|
||||||
|
/** 自定义按钮颜色, 并自动计算 `hover` 和 `active` 触发后的颜色 */
|
||||||
|
color?: string;
|
||||||
|
/** `dark` 模式, 意味着自动设置 `color` 为 `dark` 模式的颜色,默认 `false` */
|
||||||
|
dark?: boolean;
|
||||||
|
/** 自定义元素标签 */
|
||||||
|
tag?: string | Component;
|
||||||
|
/** 点击按钮后触发的回调 */
|
||||||
|
btnClick?: ({
|
||||||
|
dialog,
|
||||||
|
button
|
||||||
|
}: {
|
||||||
|
/** 当前 `Dialog` 信息 */
|
||||||
|
dialog: BtnClickDialog;
|
||||||
|
/** 当前 `button` 信息 */
|
||||||
|
button: BtnClickButton;
|
||||||
|
}) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DialogOptions extends DialogProps {
|
||||||
|
/** 内容区组件的 `props`,可通过 `defineProps` 接收 */
|
||||||
|
props?: any;
|
||||||
|
/** 是否隐藏 `Dialog` 按钮操作区的内容 */
|
||||||
|
hideFooter?: boolean;
|
||||||
|
/**
|
||||||
|
* @description 自定义对话框标题的内容渲染器
|
||||||
|
* @see {@link https://element-plus.org/zh-CN/component/dialog.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%A4%B4%E9%83%A8}
|
||||||
|
*/
|
||||||
|
headerRenderer?: ({
|
||||||
|
close,
|
||||||
|
titleId,
|
||||||
|
titleClass
|
||||||
|
}: {
|
||||||
|
close: Function;
|
||||||
|
titleId: string;
|
||||||
|
titleClass: string;
|
||||||
|
}) => VNode;
|
||||||
|
/** 自定义内容渲染器 */
|
||||||
|
contentRenderer?: ({
|
||||||
|
options,
|
||||||
|
index
|
||||||
|
}: {
|
||||||
|
options: DialogOptions;
|
||||||
|
index: number;
|
||||||
|
}) => VNode;
|
||||||
|
/** 自定义按钮操作区的内容渲染器,会覆盖`footerButtons`以及默认的 `取消` 和 `确定` 按钮 */
|
||||||
|
footerRenderer?: ({
|
||||||
|
options,
|
||||||
|
index
|
||||||
|
}: {
|
||||||
|
options: DialogOptions;
|
||||||
|
index: number;
|
||||||
|
}) => VNode;
|
||||||
|
/** 自定义底部按钮操作 */
|
||||||
|
footerButtons?: Array<ButtonProps>;
|
||||||
|
/** `Dialog` 打开后的回调 */
|
||||||
|
open?: ({
|
||||||
|
options,
|
||||||
|
index
|
||||||
|
}: {
|
||||||
|
options: DialogOptions;
|
||||||
|
index: number;
|
||||||
|
}) => void;
|
||||||
|
/** `Dialog` 关闭后的回调(只有点击右上角关闭按钮或者空白页关闭页面时才会触发) */
|
||||||
|
close?: ({
|
||||||
|
options,
|
||||||
|
index
|
||||||
|
}: {
|
||||||
|
options: DialogOptions;
|
||||||
|
index: number;
|
||||||
|
}) => void;
|
||||||
|
/** `Dialog` 关闭后的回调,会返回 `command`。`command` 值解析:`cancel` 点击取消按钮、`sure` 点击确定按钮、`close` 点击右上角关闭按钮或者空白页 */
|
||||||
|
closeCallBack?: (args: any) => void;
|
||||||
|
/** 输入焦点聚焦在 `Dialog` 内容时的回调 */
|
||||||
|
openAutoFocus?: ({
|
||||||
|
options,
|
||||||
|
index
|
||||||
|
}: {
|
||||||
|
options: DialogOptions;
|
||||||
|
index: number;
|
||||||
|
}) => void;
|
||||||
|
/** 输入焦点从 `Dialog` 内容失焦时的回调 */
|
||||||
|
closeAutoFocus?: ({
|
||||||
|
options,
|
||||||
|
index
|
||||||
|
}: {
|
||||||
|
options: DialogOptions;
|
||||||
|
index: number;
|
||||||
|
}) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };
|
Loading…
x
Reference in New Issue
Block a user