feat(@vben/playground): add typed popup data examples

This commit is contained in:
Dream
2026-08-05 09:50:55 +08:00
parent 3cbb1e8411
commit ebe0eadee4
10 changed files with 330 additions and 0 deletions

View File

@@ -1,6 +1,8 @@
<script lang="ts" setup>
import type { DrawerPlacement, DrawerState } from '@vben/common-ui';
import type { ExplicitDrawerData } from './typed-data-contract';
import { Page, useVbenDrawer } from '@vben/common-ui';
import { Button, Card } from 'antdv-next';
@@ -12,6 +14,10 @@ import DynamicDemo from './dynamic-demo.vue';
import FormDrawerDemo from './form-drawer-demo.vue';
import inContentDemo from './in-content-demo.vue';
import SharedDataDemo from './shared-data-demo.vue';
import TypedDataAutoDemo from './typed-data-auto-demo.vue';
import { useFactoryDrawer } from './typed-data-contract';
import TypedDataExplicitDemo from './typed-data-explicit-demo.vue';
import TypedDataFactoryDemo from './typed-data-factory-demo.vue';
defineOptions({ name: 'DrawerExample' });
const [BaseDrawer, baseDrawerApi] = useVbenDrawer({
@@ -42,6 +48,19 @@ const [FormDrawer, formDrawerApi] = useVbenDrawer({
connectedComponent: FormDrawerDemo,
});
const [TypedDataAutoDrawer, typedDataAutoDrawerApi] = useVbenDrawer({
connectedComponent: TypedDataAutoDemo,
});
const [TypedDataExplicitDrawer, typedDataExplicitDrawerApi] =
useVbenDrawer<ExplicitDrawerData>({
connectedComponent: TypedDataExplicitDemo,
});
const [TypedDataFactoryDrawer, typedDataFactoryDrawerApi] = useFactoryDrawer({
connectedComponent: TypedDataFactoryDemo,
});
function openBaseDrawer(placement: DrawerPlacement = 'right') {
baseDrawerApi.setState({ placement }).open();
}
@@ -93,6 +112,33 @@ function openFormDrawer() {
})
.open();
}
function openTypedDataAutoDrawer() {
typedDataAutoDrawerApi
.setData({
message: '外部无需声明泛型,由 connected component 自动推导。',
method: '自动推导',
})
.open();
}
function openTypedDataExplicitDrawer() {
typedDataExplicitDrawerApi
.setData({
message: '父子组件显式引用同一个数据类型。',
method: '显式泛型',
})
.open();
}
function openTypedDataFactoryDrawer() {
typedDataFactoryDrawerApi
.setData({
message: '父子组件复用预绑定的 typed composable。',
method: '契约工厂',
})
.open();
}
</script>
<template>
@@ -110,6 +156,9 @@ function openFormDrawer() {
<DynamicDrawer />
<SharedDataDrawer />
<FormDrawer />
<TypedDataAutoDrawer />
<TypedDataExplicitDrawer />
<TypedDataFactoryDrawer />
<Card class="mb-4" title="基本使用">
<p class="mb-3">一个基础的抽屉示例</p>
@@ -191,5 +240,30 @@ function openFormDrawer() {
打开抽屉并设置表单schema以及数据
</Button>
</Card>
<Card class="mb-4" title="共享数据:自动推导">
<p class="mb-3">
子组件 expose API父组件从 connected component 推导类型
</p>
<Button type="primary" @click="openTypedDataAutoDrawer">
打开自动推导示例
</Button>
</Card>
<Card class="mb-4" title="共享数据:显式泛型">
<p class="mb-3">无法自动推导时父子组件显式引用同一个数据类型</p>
<Button type="primary" @click="openTypedDataExplicitDrawer">
打开显式泛型示例
</Button>
</Card>
<Card class="mb-4" title="共享数据:契约工厂">
<p class="mb-3">
通过 createVbenDrawer 预绑定类型并复用 typed composable
</p>
<Button type="primary" @click="openTypedDataFactoryDrawer">
打开契约工厂示例
</Button>
</Card>
</Page>
</template>

View File

@@ -0,0 +1,29 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
interface AutoDrawerData {
message: string;
method: '自动推导';
}
const data = ref<AutoDrawerData>();
const [Drawer, drawerApi] = useVbenDrawer<AutoDrawerData>({
onOpenChange(isOpen) {
data.value = isOpen ? drawerApi.getData() : undefined;
},
});
defineExpose({ drawerApi });
</script>
<template>
<Drawer title="自动推导数据类型">
<div class="space-y-2 px-2">
<p>类型来源{{ data?.method }}</p>
<p>接收内容{{ data?.message }}</p>
</div>
</Drawer>
</template>

View File

@@ -0,0 +1,13 @@
import { createVbenDrawer } from '@vben/common-ui';
export interface ExplicitDrawerData {
message: string;
method: '显式泛型';
}
export interface FactoryDrawerData {
message: string;
method: '契约工厂';
}
export const useFactoryDrawer = createVbenDrawer<FactoryDrawerData>();

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { ExplicitDrawerData } from './typed-data-contract';
import { ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
const data = ref<ExplicitDrawerData>();
const [Drawer, drawerApi] = useVbenDrawer<ExplicitDrawerData>({
onOpenChange(isOpen) {
data.value = isOpen ? drawerApi.getData() : undefined;
},
});
</script>
<template>
<Drawer title="显式泛型数据类型">
<div class="space-y-2 px-2">
<p>类型来源{{ data?.method }}</p>
<p>接收内容{{ data?.message }}</p>
</div>
</Drawer>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { FactoryDrawerData } from './typed-data-contract';
import { ref } from 'vue';
import { useFactoryDrawer } from './typed-data-contract';
const data = ref<FactoryDrawerData>();
const [Drawer, drawerApi] = useFactoryDrawer({
onOpenChange(isOpen) {
data.value = isOpen ? drawerApi.getData() : undefined;
},
});
</script>
<template>
<Drawer title="契约工厂数据类型">
<div class="space-y-2 px-2">
<p>类型来源{{ data?.method }}</p>
<p>接收内容{{ data?.message }}</p>
</div>
</Drawer>
</template>

View File

@@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { ExplicitModalData } from './typed-data-contract';
import { onBeforeUnmount } from 'vue';
import {
@@ -22,6 +24,10 @@ import FormModalDemo from './form-modal-demo.vue';
import InContentModalDemo from './in-content-demo.vue';
import NestedDemo from './nested-demo.vue';
import SharedDataDemo from './shared-data-demo.vue';
import TypedDataAutoDemo from './typed-data-auto-demo.vue';
import { useFactoryModal } from './typed-data-contract';
import TypedDataExplicitDemo from './typed-data-explicit-demo.vue';
import TypedDataFactoryDemo from './typed-data-factory-demo.vue';
defineOptions({ name: 'ModalExample' });
@@ -55,6 +61,19 @@ const [FormModal, formModalApi] = useVbenModal({
connectedComponent: FormModalDemo,
});
const [TypedDataAutoModal, typedDataAutoModalApi] = useVbenModal({
connectedComponent: TypedDataAutoDemo,
});
const [TypedDataExplicitModal, typedDataExplicitModalApi] =
useVbenModal<ExplicitModalData>({
connectedComponent: TypedDataExplicitDemo,
});
const [TypedDataFactoryModal, typedDataFactoryModalApi] = useFactoryModal({
connectedComponent: TypedDataFactoryDemo,
});
const [NestedModal, nestedModalApi] = useVbenModal({
connectedComponent: NestedDemo,
});
@@ -113,6 +132,33 @@ function openFormModal() {
.open();
}
function openTypedDataAutoModal() {
typedDataAutoModalApi
.setData({
message: '外部无需声明泛型,由 connected component 自动推导。',
method: '自动推导',
})
.open();
}
function openTypedDataExplicitModal() {
typedDataExplicitModalApi
.setData({
message: '父子组件显式引用同一个数据类型。',
method: '显式泛型',
})
.open();
}
function openTypedDataFactoryModal() {
typedDataFactoryModalApi
.setData({
message: '父子组件复用预绑定的 typed composable。',
method: '契约工厂',
})
.open();
}
function openAlert() {
alert({
content: '这是一个弹窗',
@@ -188,6 +234,9 @@ async function openPrompt() {
<DynamicModal />
<SharedDataModal />
<FormModal />
<TypedDataAutoModal />
<TypedDataExplicitModal />
<TypedDataFactoryModal />
<NestedModal />
<BlurModal />
<Flex wrap="wrap" class="w-full" gap="10">
@@ -249,6 +298,33 @@ async function openPrompt() {
</template>
</Card>
<Card class="w-75" title="共享数据:自动推导">
<p>子组件 expose API父组件从 connected component 推导类型</p>
<template #actions>
<Button type="primary" @click="openTypedDataAutoModal">
打开自动推导示例
</Button>
</template>
</Card>
<Card class="w-75" title="共享数据:显式泛型">
<p>无法自动推导时父子组件显式引用同一个数据类型</p>
<template #actions>
<Button type="primary" @click="openTypedDataExplicitModal">
打开显式泛型示例
</Button>
</template>
</Card>
<Card class="w-75" title="共享数据:契约工厂">
<p>通过 createVbenModal 预绑定类型并复用 typed composable</p>
<template #actions>
<Button type="primary" @click="openTypedDataFactoryModal">
打开契约工厂示例
</Button>
</template>
</Card>
<Card class="w-75" title="嵌套弹窗示例">
<p>在已经打开的弹窗中再次打开弹窗</p>
<template #actions>

View File

@@ -0,0 +1,29 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
interface AutoModalData {
message: string;
method: '自动推导';
}
const data = ref<AutoModalData>();
const [Modal, modalApi] = useVbenModal<AutoModalData>({
onOpenChange(isOpen) {
data.value = isOpen ? modalApi.getData() : undefined;
},
});
defineExpose({ modalApi });
</script>
<template>
<Modal title="自动推导数据类型">
<div class="space-y-2 px-2">
<p>类型来源{{ data?.method }}</p>
<p>接收内容{{ data?.message }}</p>
</div>
</Modal>
</template>

View File

@@ -0,0 +1,13 @@
import { createVbenModal } from '@vben/common-ui';
export interface ExplicitModalData {
message: string;
method: '显式泛型';
}
export interface FactoryModalData {
message: string;
method: '契约工厂';
}
export const useFactoryModal = createVbenModal<FactoryModalData>();

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { ExplicitModalData } from './typed-data-contract';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
const data = ref<ExplicitModalData>();
const [Modal, modalApi] = useVbenModal<ExplicitModalData>({
onOpenChange(isOpen) {
data.value = isOpen ? modalApi.getData() : undefined;
},
});
</script>
<template>
<Modal title="显式泛型数据类型">
<div class="space-y-2 px-2">
<p>类型来源{{ data?.method }}</p>
<p>接收内容{{ data?.message }}</p>
</div>
</Modal>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { FactoryModalData } from './typed-data-contract';
import { ref } from 'vue';
import { useFactoryModal } from './typed-data-contract';
const data = ref<FactoryModalData>();
const [Modal, modalApi] = useFactoryModal({
onOpenChange(isOpen) {
data.value = isOpen ? modalApi.getData() : undefined;
},
});
</script>
<template>
<Modal title="契约工厂数据类型">
<div class="space-y-2 px-2">
<p>类型来源{{ data?.method }}</p>
<p>接收内容{{ data?.message }}</p>
</div>
</Modal>
</template>