123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- import type {
- DrawerApiOptions,
- DrawerProps,
- ExtendedDrawerApi,
- } from './drawer';
- import {
- defineComponent,
- h,
- inject,
- nextTick,
- onDeactivated,
- provide,
- reactive,
- ref,
- } from 'vue';
- import { useStore } from '@vben-core/shared/store';
- import { DrawerApi } from './drawer-api';
- import VbenDrawer from './drawer.vue';
- const USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');
- const DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {};
- export function setDefaultDrawerProps(props: Partial<DrawerProps>) {
- Object.assign(DEFAULT_DRAWER_PROPS, props);
- }
- export function useVbenDrawer<
- TParentDrawerProps extends DrawerProps = DrawerProps,
- >(options: DrawerApiOptions = {}) {
- // Drawer一般会抽离出来,所以如果有传入 connectedComponent,则表示为外部调用,与内部组件进行连接
- // 外部的Drawer通过provide/inject传递api
- const { connectedComponent } = options;
- if (connectedComponent) {
- const extendedApi = reactive({});
- const isDrawerReady = ref(true);
- const Drawer = defineComponent(
- (props: TParentDrawerProps, { attrs, slots }) => {
- provide(USER_DRAWER_INJECT_KEY, {
- extendApi(api: ExtendedDrawerApi) {
- // 不能直接给 reactive 赋值,会丢失响应
- // 不能用 Object.assign,会丢失 api 的原型函数
- Object.setPrototypeOf(extendedApi, api);
- },
- options,
- async reCreateDrawer() {
- isDrawerReady.value = false;
- await nextTick();
- isDrawerReady.value = true;
- },
- });
- checkProps(extendedApi as ExtendedDrawerApi, {
- ...props,
- ...attrs,
- ...slots,
- });
- return () =>
- h(
- isDrawerReady.value ? connectedComponent : 'div',
- { ...props, ...attrs },
- slots,
- );
- },
- // eslint-disable-next-line vue/one-component-per-file
- {
- name: 'VbenParentDrawer',
- inheritAttrs: false,
- },
- );
- /**
- * 在开启keepAlive情况下 直接通过浏览器按钮/手势等返回 不会关闭弹窗
- */
- onDeactivated(() => {
- (extendedApi as ExtendedDrawerApi)?.close?.();
- });
- return [Drawer, extendedApi as ExtendedDrawerApi] as const;
- }
- const injectData = inject<any>(USER_DRAWER_INJECT_KEY, {});
- const mergedOptions = {
- ...DEFAULT_DRAWER_PROPS,
- ...injectData.options,
- ...options,
- } as DrawerApiOptions;
- mergedOptions.onOpenChange = (isOpen: boolean) => {
- options.onOpenChange?.(isOpen);
- injectData.options?.onOpenChange?.(isOpen);
- };
- const onClosed = mergedOptions.onClosed;
- mergedOptions.onClosed = () => {
- onClosed?.();
- if (mergedOptions.destroyOnClose) {
- injectData.reCreateDrawer?.();
- }
- };
- const api = new DrawerApi(mergedOptions);
- const extendedApi: ExtendedDrawerApi = api as never;
- extendedApi.useStore = (selector) => {
- return useStore(api.store, selector);
- };
- const Drawer = defineComponent(
- (props: DrawerProps, { attrs, slots }) => {
- return () =>
- h(VbenDrawer, { ...props, ...attrs, drawerApi: extendedApi }, slots);
- },
- // eslint-disable-next-line vue/one-component-per-file
- {
- name: 'VbenDrawer',
- inheritAttrs: false,
- },
- );
- injectData.extendApi?.(extendedApi);
- return [Drawer, extendedApi] as const;
- }
- async function checkProps(api: ExtendedDrawerApi, attrs: Record<string, any>) {
- if (!attrs || Object.keys(attrs).length === 0) {
- return;
- }
- await nextTick();
- const state = api?.store?.state;
- if (!state) {
- return;
- }
- const stateKeys = new Set(Object.keys(state));
- for (const attr of Object.keys(attrs)) {
- if (stateKeys.has(attr) && !['class'].includes(attr)) {
- // connectedComponent存在时,不要传入Drawer的props,会造成复杂度提升,如果你需要修改Drawer的props,请使用 useVbenDrawer 或者api
- console.warn(
- `[Vben Drawer]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Drawer, please use useVbenDrawer or api.`,
- );
- }
- }
- }
|