全局抽屉动态渲染组件Global-Sheet-Manager
全局抽屉管理器:通过控制反转动态注入业务组件
#type / howto
#status / evergreen
[!info] related notes
全局抽屉动态渲染组件_Global-Sheet-Manager
- 背后的核心模式:控制反转 (IoC) / 策略模式 (Strategy)
- 抽屉只提供”壳子”,具体业务组件由调用方动态注入
目标
实现一个全局抽屉管理器,任何页面通过一行代码即可打开抽屉并渲染指定组件,避免在每个页面重复编写抽屉壳子。
前置条件
- Vue 3 +
<script setup> - UI 库的 Drawer 组件(如 Element Plus el-drawer / shadcn Sheet)
步骤
1. 定义 Sheet 状态管理
// composables/useSheet.ts
import { ref, shallowRef, markRaw, type Component } from 'vue';
interface SheetOptions {
component: Component;
props?: Record<string, any>;
title?: string;
width?: string;
}
const isVisible = ref(false);
const currentComponent = shallowRef<Component | null>(null);
const currentProps = ref<Record<string, any>>({});
const currentTitle = ref('');
const currentWidth = ref('40%');
export function useSheet() {
function openSheet(options: SheetOptions) {
currentComponent.value = markRaw(options.component);
currentProps.value = options.props ?? {};
currentTitle.value = options.title ?? '';
currentWidth.value = options.width ?? '40%';
isVisible.value = true;
}
function closeSheet() {
isVisible.value = false;
// 延迟清空,避免关闭动画期间组件消失
setTimeout(() => {
currentComponent.value = null;
currentProps.value = {};
}, 300);
}
return {
isVisible,
currentComponent,
currentProps,
currentTitle,
currentWidth,
openSheet,
closeSheet,
};
}
2. 全局 Sheet 壳子组件
<!-- components/GlobalSheet.vue -->
<template>
<el-drawer
v-model="isVisible"
:title="currentTitle"
:size="currentWidth"
@close="closeSheet"
>
<component
v-if="currentComponent"
:is="currentComponent"
v-bind="currentProps"
@close="closeSheet"
/>
</el-drawer>
</template>
<script setup>
import { useSheet } from '@/composables/useSheet';
const { isVisible, currentComponent, currentProps, currentTitle, currentWidth, closeSheet } = useSheet();
</script>
3. App.vue 挂载
<template>
<router-view />
<GlobalSheet />
</template>
4. 业务组件调用
<script setup>
import { useSheet } from '@/composables/useSheet';
import EditUserForm from './EditUserForm.vue';
const { openSheet } = useSheet();
function handleEdit(user) {
openSheet({
component: EditUserForm,
props: { userId: user.id },
title: '编辑用户',
width: '500px',
});
}
</script>
验证
- 调用
openSheet()后抽屉弹出,内部正确渲染传入的组件 - 组件内部可通过
emit('close')关闭抽屉 - 关闭后再次打开不同组件,确认无残留状态(旧组件已销毁)