feat: add useAlertContext
for Alert component (#5947)
* 新增Alert的子组件中获取弹窗上下文的能力
This commit is contained in:
parent
9700150653
commit
bf7496f0d5
@ -12,6 +12,12 @@ Alert提供的功能与Modal类似,但只适用于简单应用场景。例如
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
::: tip 注意
|
||||||
|
|
||||||
|
Alert提供的快捷方法alert、confirm、prompt动态创建的弹窗在已打开的情况下,不支持HMR(热更新),代码变更后需要关闭这些弹窗后重新打开。
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
::: tip README
|
::: tip README
|
||||||
|
|
||||||
下方示例代码中的,存在一些主题色未适配、样式缺失的问题,这些问题只在文档内会出现,实际使用并不会有这些问题,可忽略,不必纠结。
|
下方示例代码中的,存在一些主题色未适配、样式缺失的问题,这些问题只在文档内会出现,实际使用并不会有这些问题,可忽略,不必纠结。
|
||||||
@ -32,6 +38,19 @@ Alert提供的功能与Modal类似,但只适用于简单应用场景。例如
|
|||||||
|
|
||||||
<DemoPreview dir="demos/vben-alert/prompt" />
|
<DemoPreview dir="demos/vben-alert/prompt" />
|
||||||
|
|
||||||
|
## useAlertContext
|
||||||
|
|
||||||
|
当弹窗的content、footer、icon使用自定义组件时,在这些组件中可以使用 `useAlertContext` 获取当前弹窗的上下文对象,用来主动控制弹窗。
|
||||||
|
|
||||||
|
::: tip 注意 `useAlertContext`只能用在setup或者函数式组件中。:::
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
| 方法 | 描述 | 类型 | 版本要求 |
|
||||||
|
| --------- | ------------------ | -------- | -------- |
|
||||||
|
| doConfirm | 调用弹窗的确认操作 | ()=>void | >5.5.4 |
|
||||||
|
| doCancel | 调用弹窗的取消操作 | ()=>void | >5.5.4 |
|
||||||
|
|
||||||
## 类型说明
|
## 类型说明
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
import { alert, prompt, VbenButton } from '@vben/common-ui';
|
import { alert, prompt, useAlertContext, VbenButton } from '@vben/common-ui';
|
||||||
|
|
||||||
import { Input, RadioGroup, Select } from 'ant-design-vue';
|
import { Input, RadioGroup, Select } from 'ant-design-vue';
|
||||||
import { BadgeJapaneseYen } from 'lucide-vue-next';
|
import { BadgeJapaneseYen } from 'lucide-vue-next';
|
||||||
@ -20,16 +20,30 @@ function showPrompt() {
|
|||||||
|
|
||||||
function showSlotsPrompt() {
|
function showSlotsPrompt() {
|
||||||
prompt({
|
prompt({
|
||||||
component: Input,
|
component: () => {
|
||||||
componentProps: {
|
// 获取弹窗上下文。注意:只能在setup或者函数式组件中调用
|
||||||
|
const { doConfirm } = useAlertContext();
|
||||||
|
return h(
|
||||||
|
Input,
|
||||||
|
{
|
||||||
|
onKeydown(e: KeyboardEvent) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
// 调用弹窗提供的确认方法
|
||||||
|
doConfirm();
|
||||||
|
}
|
||||||
|
},
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
prefix: '充值金额',
|
prefix: '充值金额:',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
componentSlots: {
|
{
|
||||||
addonAfter: () => h(BadgeJapaneseYen),
|
addonAfter: () => h(BadgeJapaneseYen),
|
||||||
},
|
},
|
||||||
content: '此弹窗演示了如何使用componentSlots传递自定义插槽',
|
);
|
||||||
|
},
|
||||||
|
content:
|
||||||
|
'此弹窗演示了如何使用自定义插槽,并且可以使用useAlertContext获取到弹窗的上下文。\n在输入框中按下回车键会触发确认操作。',
|
||||||
icon: 'question',
|
icon: 'question',
|
||||||
modelPropName: 'value',
|
modelPropName: 'value',
|
||||||
}).then((val) => {
|
}).then((val) => {
|
||||||
|
@ -7,7 +7,7 @@ import type { AlertProps, BeforeCloseScope, PromptProps } from './alert';
|
|||||||
import { h, nextTick, ref, render } from 'vue';
|
import { h, nextTick, ref, render } from 'vue';
|
||||||
|
|
||||||
import { useSimpleLocale } from '@vben-core/composables';
|
import { useSimpleLocale } from '@vben-core/composables';
|
||||||
import { Input } from '@vben-core/shadcn-ui';
|
import { Input, VbenRenderContent } from '@vben-core/shadcn-ui';
|
||||||
import { isFunction, isString } from '@vben-core/shared/utils';
|
import { isFunction, isString } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import Alert from './alert.vue';
|
import Alert from './alert.vue';
|
||||||
@ -146,11 +146,7 @@ export async function vbenPrompt<T = any>(
|
|||||||
const inputComponentRef = ref<null | VNode>(null);
|
const inputComponentRef = ref<null | VNode>(null);
|
||||||
const staticContents: Component[] = [];
|
const staticContents: Component[] = [];
|
||||||
|
|
||||||
if (isString(content)) {
|
staticContents.push(h(VbenRenderContent, { content, renderBr: true }));
|
||||||
staticContents.push(h('span', content));
|
|
||||||
} else if (content) {
|
|
||||||
staticContents.push(content as Component);
|
|
||||||
}
|
|
||||||
|
|
||||||
const modelPropName = _modelPropName || 'modelValue';
|
const modelPropName = _modelPropName || 'modelValue';
|
||||||
const componentProps = { ..._componentProps };
|
const componentProps = { ..._componentProps };
|
||||||
|
@ -2,6 +2,8 @@ import type { Component, VNode, VNodeArrayChildren } from 'vue';
|
|||||||
|
|
||||||
import type { Recordable } from '@vben-core/typings';
|
import type { Recordable } from '@vben-core/typings';
|
||||||
|
|
||||||
|
import { createContext } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
export type IconType = 'error' | 'info' | 'question' | 'success' | 'warning';
|
export type IconType = 'error' | 'info' | 'question' | 'success' | 'warning';
|
||||||
|
|
||||||
export type BeforeCloseScope = {
|
export type BeforeCloseScope = {
|
||||||
@ -70,3 +72,28 @@ export type PromptProps<T = any> = {
|
|||||||
/** 输入组件的值属性名 */
|
/** 输入组件的值属性名 */
|
||||||
modelPropName?: string;
|
modelPropName?: string;
|
||||||
} & Omit<AlertProps, 'beforeClose'>;
|
} & Omit<AlertProps, 'beforeClose'>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alert上下文
|
||||||
|
*/
|
||||||
|
export type AlertContext = {
|
||||||
|
/** 执行取消操作 */
|
||||||
|
doCancel: () => void;
|
||||||
|
/** 执行确认操作 */
|
||||||
|
doConfirm: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const [injectAlertContext, provideAlertContext] =
|
||||||
|
createContext<AlertContext>('VbenAlertContext');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Alert上下文
|
||||||
|
* @returns AlertContext
|
||||||
|
*/
|
||||||
|
export function useAlertContext() {
|
||||||
|
const context = injectAlertContext();
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('useAlertContext must be used within an AlertProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
@ -28,6 +28,8 @@ import {
|
|||||||
import { globalShareState } from '@vben-core/shared/global-state';
|
import { globalShareState } from '@vben-core/shared/global-state';
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { provideAlertContext } from './alert';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<AlertProps>(), {
|
const props = withDefaults(defineProps<AlertProps>(), {
|
||||||
bordered: true,
|
bordered: true,
|
||||||
buttonAlign: 'end',
|
buttonAlign: 'end',
|
||||||
@ -87,6 +89,23 @@ const getIconRender = computed(() => {
|
|||||||
}
|
}
|
||||||
return iconRender;
|
return iconRender;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function doCancel() {
|
||||||
|
isConfirm.value = false;
|
||||||
|
handleOpenChange(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doConfirm() {
|
||||||
|
isConfirm.value = true;
|
||||||
|
handleOpenChange(false);
|
||||||
|
emits('confirm');
|
||||||
|
}
|
||||||
|
|
||||||
|
provideAlertContext({
|
||||||
|
doCancel,
|
||||||
|
doConfirm,
|
||||||
|
});
|
||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
isConfirm.value = true;
|
isConfirm.value = true;
|
||||||
emits('confirm');
|
emits('confirm');
|
||||||
@ -152,7 +171,7 @@ async function handleOpenChange(val: boolean) {
|
|||||||
</div>
|
</div>
|
||||||
</AlertDialogTitle>
|
</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
<div class="m-4 mb-6 min-h-[30px]">
|
<div class="m-4 min-h-[30px]">
|
||||||
<VbenRenderContent :content="content" render-br />
|
<VbenRenderContent :content="content" render-br />
|
||||||
</div>
|
</div>
|
||||||
<VbenLoading v-if="loading && contentMasking" :spinning="loading" />
|
<VbenLoading v-if="loading && contentMasking" :spinning="loading" />
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
export * from './alert';
|
export type {
|
||||||
|
AlertProps,
|
||||||
|
BeforeCloseScope,
|
||||||
|
IconType,
|
||||||
|
PromptProps,
|
||||||
|
} from './alert';
|
||||||
|
export { useAlertContext } from './alert';
|
||||||
export { default as Alert } from './alert.vue';
|
export { default as Alert } from './alert.vue';
|
||||||
export {
|
export {
|
||||||
vbenAlert as alert,
|
vbenAlert as alert,
|
||||||
|
@ -31,12 +31,11 @@ export default defineComponent({
|
|||||||
if (props.renderBr && isString(props.content)) {
|
if (props.renderBr && isString(props.content)) {
|
||||||
const lines = props.content.split('\n');
|
const lines = props.content.split('\n');
|
||||||
const result = [];
|
const result = [];
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (const [i, line] of lines.entries()) {
|
||||||
const line = lines[i];
|
result.push(h('p', { key: i }, line));
|
||||||
result.push(h('span', { key: i }, line));
|
// if (i < lines.length - 1) {
|
||||||
if (i < lines.length - 1) {
|
// result.push(h('br'));
|
||||||
result.push(h('br'));
|
// }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user