ソースを参照

perf: improve destroyOnClose for VbenDrawer&VbenModal (#6051)

* fix: fix that the default value of modal destroyOnClose does not take effect

* perf: improve destroyOnClose for VbenDrawer
ming4762 2 週間 前
コミット
0cc1cb5a7b

+ 4 - 4
packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts

@@ -52,6 +52,10 @@ export interface DrawerProps {
    * 弹窗描述
    */
   description?: string;
+  /**
+   * 在关闭时销毁抽屉
+   */
+  destroyOnClose?: boolean;
   /**
    * 是否显示底部
    * @default true
@@ -143,10 +147,6 @@ export interface DrawerApiOptions extends DrawerState {
    * 独立的抽屉组件
    */
   connectedComponent?: Component;
-  /**
-   * 在关闭时销毁抽屉。仅在使用 connectedComponent 时有效
-   */
-  destroyOnClose?: boolean;
   /**
    * 关闭前的回调,返回 false 可以阻止关闭
    * @returns

+ 29 - 2
packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue

@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import type { DrawerProps, ExtendedDrawerApi } from './drawer';
 
-import { computed, provide, ref, useId, watch } from 'vue';
+import { computed, provide, ref, unref, useId, watch } from 'vue';
 
 import {
   useIsMobile,
@@ -35,6 +35,7 @@ interface Props extends DrawerProps {
 const props = withDefaults(defineProps<Props>(), {
   appendToMain: false,
   closeIconPlacement: 'right',
+  destroyOnClose: true,
   drawerApi: undefined,
   submitting: false,
   zIndex: 1000,
@@ -63,6 +64,7 @@ const {
   confirmText,
   contentClass,
   description,
+  destroyOnClose,
   footer: showFooter,
   footerClass,
   header: showHeader,
@@ -131,6 +133,29 @@ const getAppendTo = computed(() => {
     ? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`
     : undefined;
 });
+
+/**
+ * destroyOnClose功能完善
+ */
+// 是否打开过
+const hasOpened = ref(false);
+const isClosed = ref(true);
+watch(
+  () => state?.value?.isOpen,
+  (value) => {
+    isClosed.value = false;
+    if (value && !unref(hasOpened)) {
+      hasOpened.value = true;
+    }
+  },
+);
+function handleClosed() {
+  isClosed.value = true;
+  props.drawerApi?.onClosed();
+}
+const getForceMount = computed(() => {
+  return !unref(destroyOnClose) && unref(hasOpened);
+});
 </script>
 <template>
   <Sheet
@@ -144,15 +169,17 @@ const getAppendTo = computed(() => {
         cn('flex w-[520px] flex-col', drawerClass, {
           '!w-full': isMobile || placement === 'bottom' || placement === 'top',
           'max-h-[100vh]': placement === 'bottom' || placement === 'top',
+          hidden: isClosed,
         })
       "
       :modal="modal"
       :open="state?.isOpen"
       :side="placement"
       :z-index="zIndex"
+      :force-mount="getForceMount"
       :overlay-blur="overlayBlur"
       @close-auto-focus="handleFocusOutside"
-      @closed="() => drawerApi?.onClosed()"
+      @closed="handleClosed"
       @escape-key-down="escapeKeyDown"
       @focus-outside="handleFocusOutside"
       @interact-outside="interactOutside"

+ 3 - 1
packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts

@@ -21,7 +21,9 @@ import VbenDrawer from './drawer.vue';
 
 const USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');
 
-const DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {};
+const DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {
+  destroyOnClose: true,
+};
 
 export function setDefaultDrawerProps(props: Partial<DrawerProps>) {
   Object.assign(DEFAULT_DRAWER_PROPS, props);

+ 4 - 2
packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts

@@ -17,7 +17,9 @@ import VbenModal from './modal.vue';
 
 const USER_MODAL_INJECT_KEY = Symbol('VBEN_MODAL_INJECT');
 
-const DEFAULT_MODAL_PROPS: Partial<ModalProps> = {};
+const DEFAULT_MODAL_PROPS: Partial<ModalProps> = {
+  destroyOnClose: true,
+};
 
 export function setDefaultModalProps(props: Partial<ModalProps>) {
   Object.assign(DEFAULT_MODAL_PROPS, props);
@@ -86,7 +88,7 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
 
   mergedOptions.onClosed = () => {
     options.onClosed?.();
-    if (options.destroyOnClose) {
+    if (mergedOptions.destroyOnClose) {
       injectData.reCreateModal?.();
     }
   };

+ 24 - 2
playground/src/views/examples/drawer/in-content-demo.vue

@@ -5,9 +5,27 @@ import { useVbenDrawer } from '@vben/common-ui';
 
 import { Input, message } from 'ant-design-vue';
 
+import { useVbenForm } from '#/adapter/form';
+
 const value = ref('');
 
+const [Form] = useVbenForm({
+  schema: [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'KeepAlive测试:内部组件',
+      },
+      fieldName: 'field1',
+      hideLabel: true,
+      label: '字段1',
+    },
+  ],
+  showDefaultActions: false,
+});
+
 const [Drawer, drawerApi] = useVbenDrawer({
+  destroyOnClose: false,
   onCancel() {
     drawerApi.close();
   },
@@ -20,7 +38,11 @@ const [Drawer, drawerApi] = useVbenDrawer({
 <template>
   <Drawer append-to-main title="基础抽屉示例" title-tooltip="标题提示内容">
     <template #extra> extra </template>
-    本抽屉指定在内容区域打开
-    <Input v-model="value" placeholder="KeepAlive测试" />
+    此弹窗指定在内容区域打开,并且在关闭之后弹窗内容不会被销毁
+    <Input
+      v-model:value="value"
+      placeholder="KeepAlive测试:connectedComponent"
+    />
+    <Form />
   </Drawer>
 </template>