mirror of
https://github.com/keven1024/015.git
synced 2026-05-31 17:39:35 +00:00
feat(front): update GlobalDrawer component to support async close handling and improve drawer visibility management
This commit is contained in:
@@ -1,43 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import { Drawer, DrawerContent } from '@/components/ui/drawer'
|
||||
import { createVNode } from 'vue'
|
||||
import type { VNode } from 'vue'
|
||||
import useStore from '@/composables/useStore'
|
||||
import { isFunction } from 'lodash-es'
|
||||
|
||||
type DrawerOnclose<T = unknown> = (data?: T) => void
|
||||
type DrawerOnclose<T = unknown> = (data?: T) => Promise<void>
|
||||
type DrawerRender<T = unknown> = VNode | ((props: { hide: DrawerOnclose<T> }) => VNode)
|
||||
export type DrawerItem<T = unknown> = {
|
||||
render?: DrawerRender<T>
|
||||
onClose: DrawerOnclose<T>
|
||||
key: string
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
const store = useStore()
|
||||
const currentDrawer = computed(() => store.drawer?.[store.drawer?.length - 1])
|
||||
|
||||
const render = computed(() => currentDrawer?.value?.render)
|
||||
const hide = computed(() => currentDrawer?.value?.onClose)
|
||||
const Children = () =>
|
||||
render.value
|
||||
? createVNode(render.value, {
|
||||
hide: hide?.value,
|
||||
})
|
||||
: null
|
||||
const Children = ({ drawer }: { drawer: DrawerItem }) => {
|
||||
if (!drawer.render) {
|
||||
return null
|
||||
}
|
||||
return isFunction(drawer.render) ? drawer.render({ hide: drawer.onClose }) : drawer.render
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer
|
||||
:open="!!store.drawer?.[store.drawer?.length - 1]"
|
||||
v-for="item in store.drawer"
|
||||
:key="item.key"
|
||||
:open="item.visible"
|
||||
@update:open="
|
||||
(open) => {
|
||||
if (!open && store?.drawer?.length && hide) {
|
||||
hide()
|
||||
if (!open) {
|
||||
item.onClose()
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<DrawerContent>
|
||||
<div class="mx-auto min-w-lg max-w-[80vw] pb-10 px-3">
|
||||
<Children />
|
||||
<Children :drawer="item" />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { DrawerItem } from '~/components/GlobalDrawer.vue'
|
||||
import asyncWait from './asyncWait'
|
||||
|
||||
type DrawerProps<T = unknown> = Pick<DrawerItem<T>, 'render'>
|
||||
|
||||
@@ -6,12 +7,14 @@ function showDrawer<T = unknown>(props: DrawerProps<T>): Promise<T | undefined>
|
||||
const key = Math.random().toString(36).slice(2, 8)
|
||||
return new Promise((res) => {
|
||||
const { render } = props || {}
|
||||
const onClose = (data?: T) => {
|
||||
store.drawer = (store.drawer ?? [])?.filter((item) => item.key !== key)
|
||||
const store = useStore()
|
||||
const onClose = async (data?: T) => {
|
||||
store.drawer = store.drawer?.map((d) => (d.key === key ? { ...d, visible: false } : d))
|
||||
await asyncWait(500)
|
||||
store.drawer = (store.drawer ?? []).filter((d) => d.key !== key)
|
||||
res(data)
|
||||
}
|
||||
const store = useStore()
|
||||
store.drawer = [...(store.drawer || []), { render, onClose, key }]
|
||||
store.drawer = [...(store.drawer || []), { render, onClose, key, visible: true }]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,38 @@ if (!isDev) {
|
||||
@click="
|
||||
async () => {
|
||||
await showDrawer({
|
||||
render: ({ ...rest }) => h('div', { style: { height: '30vh' } }, '内容'),
|
||||
render: ({ hide }) =>
|
||||
h('div', { class: 'flex h-[30vh] flex-col gap-4' }, [
|
||||
h('div', '第一层内容'),
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
variant: 'outline',
|
||||
onClick: () =>
|
||||
showDrawer({
|
||||
render: ({ hide: hideInner }) =>
|
||||
h('div', { class: 'flex h-[30vh] flex-col gap-4' }, [
|
||||
h('div', '第二层内容'),
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
onClick: () => hideInner(),
|
||||
},
|
||||
() => '关闭第二层'
|
||||
),
|
||||
]),
|
||||
}),
|
||||
},
|
||||
() => '打开第二层(showDrawer)'
|
||||
),
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
onClick: () => hide(),
|
||||
},
|
||||
() => '关闭第一层'
|
||||
),
|
||||
]),
|
||||
})
|
||||
toast.success('被关闭')
|
||||
}
|
||||
@@ -72,7 +103,6 @@ if (!isDev) {
|
||||
</FormButton>
|
||||
</div>
|
||||
</VeeForm>
|
||||
<div>测试dayjs语言包渲染:{{ dayjs().add(1, 'day').fromNow() }}</div>
|
||||
</BaseCard>
|
||||
</template>
|
||||
<style scoped></style>
|
||||
|
||||
Reference in New Issue
Block a user