docs: document typed popup data contracts
This commit is contained in:
@@ -50,6 +50,29 @@ Drawer 内的内容一般业务中,会比较复杂,所以我们可以将 dra
|
||||
|
||||
<DemoPreview dir="demos/vben-drawer/shared-data" />
|
||||
|
||||
### 数据类型约束
|
||||
|
||||
推荐在 connected 子组件中声明一次数据类型并暴露 `drawerApi`,外部会从 `connectedComponent` 自动推导 `setData` 和 `getData` 的类型:
|
||||
|
||||
```ts
|
||||
// connected 子组件
|
||||
const [Drawer, drawerApi] = useVbenDrawer<EditData>();
|
||||
defineExpose({ drawerApi });
|
||||
|
||||
// 外部组件,无需重复声明 EditData
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: EditDrawer,
|
||||
});
|
||||
```
|
||||
|
||||
无法从组件公开实例推导时,可以显式使用 `useVbenDrawer<EditData>()`。需要让多个文件共享同一契约时,可以在独立模块中预绑定:
|
||||
|
||||
```ts
|
||||
export const useEditDrawer = createVbenDrawer<EditData>();
|
||||
```
|
||||
|
||||
三种方式的优先级为:显式泛型、connected component 自动推导、`unknown`。普通 SFC 通过 `defineExpose` 支持自动推导;泛型 SFC、函数式组件或被标注为宽 `Component` 的组件应使用显式泛型或契约工厂。`getData()` 在尚未调用 `setData()` 时返回 `undefined`,业务允许 `null`、部分对象等值时,需要在数据泛型中准确声明。
|
||||
|
||||
::: info 注意
|
||||
|
||||
- `VbenDrawer` 组件对于参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenDrawer参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。
|
||||
@@ -143,8 +166,8 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
| setState | 动态设置抽屉状态属性 | `(((prev: DrawerState) => Partial<DrawerState>)\| Partial<DrawerState>)=>drawerApi` |
|
||||
| open | 打开弹窗 | `()=>void` | --- |
|
||||
| close | 关闭弹窗 | `()=>void` | --- |
|
||||
| setData | 设置共享数据 | `<T>(data:T)=>drawerApi` | --- |
|
||||
| getData | 获取共享数据 | `<T>()=>T` | --- |
|
||||
| setData | 设置共享数据 | `(data:TData)=>drawerApi` | --- |
|
||||
| getData | 获取共享数据 | `()=>TData\|undefined` | --- |
|
||||
| useStore | 获取可响应式状态 | - | --- |
|
||||
| lock | 将抽屉标记为提交中,锁定当前状态 | `(isLock:boolean)=>drawerApi` | >5.5.3 |
|
||||
| unlock | lock方法的反操作,解除抽屉的锁定状态,也是lock(false)的别名 | `()=>drawerApi` | >5.5.3 |
|
||||
|
||||
@@ -56,6 +56,29 @@ Modal 内的内容一般业务中,会比较复杂,所以我们可以将 moda
|
||||
|
||||
<DemoPreview dir="demos/vben-modal/shared-data" />
|
||||
|
||||
### 数据类型约束
|
||||
|
||||
推荐在 connected 子组件中声明一次数据类型并暴露 `modalApi`,外部会从 `connectedComponent` 自动推导 `setData` 和 `getData` 的类型:
|
||||
|
||||
```ts
|
||||
// connected 子组件
|
||||
const [Modal, modalApi] = useVbenModal<EditData>();
|
||||
defineExpose({ modalApi });
|
||||
|
||||
// 外部组件,无需重复声明 EditData
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
connectedComponent: EditModal,
|
||||
});
|
||||
```
|
||||
|
||||
无法从组件公开实例推导时,可以显式使用 `useVbenModal<EditData>()`。需要让多个文件共享同一契约时,可以在独立模块中预绑定:
|
||||
|
||||
```ts
|
||||
export const useEditModal = createVbenModal<EditData>();
|
||||
```
|
||||
|
||||
三种方式的优先级为:显式泛型、connected component 自动推导、`unknown`。普通 SFC 通过 `defineExpose` 支持自动推导;泛型 SFC、函数式组件或被标注为宽 `Component` 的组件应使用显式泛型或契约工厂。`getData()` 在尚未调用 `setData()` 时返回 `undefined`,业务允许 `null`、部分对象等值时,需要在数据泛型中准确声明。
|
||||
|
||||
## 动画类型
|
||||
|
||||
通过 `animationType` 属性可以控制弹窗的动画效果:
|
||||
@@ -162,8 +185,8 @@ const [Modal, modalApi] = useVbenModal({
|
||||
| setState | 动态设置弹窗状态属性 | `(((prev: ModalState) => Partial<ModalState>)\| Partial<ModalState>)=>modalApi` | - |
|
||||
| open | 打开弹窗 | `()=>void` | - |
|
||||
| close | 关闭弹窗 | `()=>void` | - |
|
||||
| setData | 设置共享数据 | `<T>(data:T)=>modalApi` | - |
|
||||
| getData | 获取共享数据 | `<T>()=>T` | - |
|
||||
| setData | 设置共享数据 | `(data:TData)=>modalApi` | - |
|
||||
| getData | 获取共享数据 | `()=>TData\|undefined` | - |
|
||||
| useStore | 获取可响应式状态 | - | - |
|
||||
| lock | 将弹窗标记为提交中,锁定当前状态 | `(isLock:boolean)=>modalApi` | >5.5.2 |
|
||||
| unlock | lock方法的反操作,解除弹窗的锁定状态,也是lock(false)的别名 | `()=>modalApi` | >5.5.3 |
|
||||
|
||||
@@ -3,9 +3,14 @@ import { ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
|
||||
const data = ref();
|
||||
interface SharedData {
|
||||
content: string;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
const data = ref<SharedData>();
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer<SharedData>({
|
||||
onCancel() {
|
||||
drawerApi.close();
|
||||
},
|
||||
@@ -14,10 +19,12 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
},
|
||||
onOpenChange(isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
data.value = drawerApi.getData<Record<string, any>>();
|
||||
data.value = drawerApi.getData();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
defineExpose({ drawerApi });
|
||||
</script>
|
||||
<template>
|
||||
<Drawer title="数据共享示例">
|
||||
|
||||
@@ -3,9 +3,14 @@ import { ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
const data = ref();
|
||||
interface SharedData {
|
||||
content: string;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
const data = ref<SharedData>();
|
||||
|
||||
const [Modal, modalApi] = useVbenModal<SharedData>({
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
@@ -14,10 +19,12 @@ const [Modal, modalApi] = useVbenModal({
|
||||
},
|
||||
onOpenChange(isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
data.value = modalApi.getData<Record<string, any>>();
|
||||
data.value = modalApi.getData();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
defineExpose({ modalApi });
|
||||
</script>
|
||||
<template>
|
||||
<Modal title="数据共享示例">
|
||||
|
||||
@@ -23,6 +23,29 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
- Default drawer behavior can be adjusted in `apps/<app>/src/bootstrap.ts` through `setDefaultDrawerProps(...)`.
|
||||
- `setState(...)` works on `DrawerState`, not `ModalState`.
|
||||
|
||||
## Shared Data Types
|
||||
|
||||
The recommended approach is to declare the data type once in the connected component and expose `drawerApi`. The outer call then infers the data contract from `connectedComponent`:
|
||||
|
||||
```ts
|
||||
// Connected component
|
||||
const [Drawer, drawerApi] = useVbenDrawer<EditData>();
|
||||
defineExpose({ drawerApi });
|
||||
|
||||
// Outer component, EditData is inferred
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: EditDrawer,
|
||||
});
|
||||
```
|
||||
|
||||
Use `useVbenDrawer<EditData>()` explicitly when the component type cannot expose the contract. For larger features, pre-bind one reusable contract in a separate module:
|
||||
|
||||
```ts
|
||||
export const useEditDrawer = createVbenDrawer<EditData>();
|
||||
```
|
||||
|
||||
The precedence is explicit generic, connected component inference, then `unknown`. Plain SFCs support inference through `defineExpose`; generic SFCs, functional components, and components widened to `Component` should use an explicit generic or contract factory. `getData()` returns `undefined` before `setData()` is called. Include `null` or partial payloads in the data type when they are valid business values.
|
||||
|
||||
## Key Props
|
||||
|
||||
| Prop | Description | Type |
|
||||
@@ -50,7 +73,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
| `setState(...)` | updates drawer state |
|
||||
| `open()` | opens the drawer |
|
||||
| `close()` | closes the drawer |
|
||||
| `setData(data)` | stores shared data |
|
||||
| `getData<T>()` | reads shared data |
|
||||
| `setData(data: TData)` | stores typed shared data |
|
||||
| `getData()` | returns `TData \| undefined` |
|
||||
| `lock(isLocked = true)` | locks the drawer into submitting state |
|
||||
| `unlock()` | alias for `lock(false)` |
|
||||
|
||||
@@ -23,6 +23,29 @@ const [Modal, modalApi] = useVbenModal({
|
||||
- When `connectedComponent` is present, avoid pushing extra modal props through the connected side. Prefer `useVbenModal(...)` or `modalApi.setState(...)`.
|
||||
- Default modal behavior can be adjusted in `apps/<app>/src/bootstrap.ts` through `setDefaultModalProps(...)`.
|
||||
|
||||
## Shared Data Types
|
||||
|
||||
The recommended approach is to declare the data type once in the connected component and expose `modalApi`. The outer call then infers the data contract from `connectedComponent`:
|
||||
|
||||
```ts
|
||||
// Connected component
|
||||
const [Modal, modalApi] = useVbenModal<EditData>();
|
||||
defineExpose({ modalApi });
|
||||
|
||||
// Outer component, EditData is inferred
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
connectedComponent: EditModal,
|
||||
});
|
||||
```
|
||||
|
||||
Use `useVbenModal<EditData>()` explicitly when the component type cannot expose the contract. For larger features, pre-bind one reusable contract in a separate module:
|
||||
|
||||
```ts
|
||||
export const useEditModal = createVbenModal<EditData>();
|
||||
```
|
||||
|
||||
The precedence is explicit generic, connected component inference, then `unknown`. Plain SFCs support inference through `defineExpose`; generic SFCs, functional components, and components widened to `Component` should use an explicit generic or contract factory. `getData()` returns `undefined` before `setData()` is called. Include `null` or partial payloads in the data type when they are valid business values.
|
||||
|
||||
## Key Props
|
||||
|
||||
| Prop | Description | Type |
|
||||
@@ -50,7 +73,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
| `setState(...)` | updates modal state |
|
||||
| `open()` | opens the modal |
|
||||
| `close()` | closes the modal |
|
||||
| `setData(data)` | stores shared data |
|
||||
| `getData<T>()` | reads shared data |
|
||||
| `setData(data: TData)` | stores typed shared data |
|
||||
| `getData()` | returns `TData \| undefined` |
|
||||
| `lock(isLocked = true)` | locks the modal into submitting state |
|
||||
| `unlock()` | alias for `lock(false)` |
|
||||
|
||||
Reference in New Issue
Block a user