Browse Source

fix(modal): fix modal not showing footer

vben 4 years ago
parent
commit
fb0c7763ed

+ 7 - 0
CHANGELOG.zh_CN.md

@@ -1,8 +1,15 @@
 ## Wip
 
+### 🎫 Chores
+
+- 添加部分注释
+- pwa 图标补充
+- types 类型调整
+
 ### 🐛 Bug Fixes
 
 - 修复本地代理 post 接口到 https 地址超时错误
+- 修复 modal 在不显示 footer 的时候全屏高度计算问题
 
 ## 2.0.0-rc.6 (2020-10-28)
 

+ 2 - 1
src/components/Authority/src/index.vue

@@ -1,5 +1,6 @@
 <script lang="ts">
-  import { defineComponent, PropType, computed, unref } from 'vue';
+  import type { PropType } from 'vue';
+  import { defineComponent, computed, unref } from 'vue';
 
   import { PermissionModeEnum } from '/@/enums/appEnum';
   import { RoleEnum } from '/@/enums/roleEnum';

+ 1 - 3
src/components/Basic/src/BasicArrow.vue

@@ -7,11 +7,10 @@
   import type { PropType } from 'vue';
 
   import { defineComponent, computed } from 'vue';
-
   import { RightOutlined } from '@ant-design/icons-vue';
 
   export default defineComponent({
-    name: 'BaseArrow',
+    name: 'BasicArrow',
     components: { RightOutlined },
     props: {
       // Expand contract, expand by default
@@ -24,7 +23,6 @@
       const getClass = computed(() => {
         const preCls = 'base-arrow';
         const cls = [preCls];
-
         props.expand && cls.push(`${preCls}__active`);
         return cls;
       });

+ 5 - 3
src/components/Basic/src/BasicHelp.vue

@@ -1,16 +1,15 @@
 <script lang="ts">
   import type { PropType } from 'vue';
+  import { defineComponent, computed, unref, h } from 'vue';
 
   import { Tooltip } from 'ant-design-vue';
   import { InfoCircleOutlined } from '@ant-design/icons-vue';
-  import { defineComponent, computed, unref, h } from 'vue';
 
   import { getPopupContainer } from '/@/utils';
-
   import { isString, isArray } from '/@/utils/is';
   import { getSlot } from '/@/utils/helper/tsxHelper';
   export default defineComponent({
-    name: 'BaseHelp',
+    name: 'BasicHelp',
     components: { Tooltip },
     props: {
       // max-width
@@ -56,12 +55,14 @@
           maxWidth: props.maxWidth,
         };
       });
+
       const getWrapStyleRef = computed(() => {
         return {
           color: props.color,
           fontSize: props.fontSize,
         };
       });
+
       const getMainStyleRef = computed(() => {
         return props.absolute ? props.position : {};
       });
@@ -81,6 +82,7 @@
         }
         return null;
       };
+
       return () => {
         return h(
           Tooltip,

+ 5 - 2
src/components/Basic/src/BasicTitle.vue

@@ -1,7 +1,7 @@
 <template>
   <span class="base-title" :class="{ 'show-span': showSpan && $slots.default }">
     <slot />
-    <BaseHelp class="base-title__help" v-if="helpMessage" :text="helpMessage" />
+    <BasicHelp class="base-title__help" v-if="helpMessage" :text="helpMessage" />
   </span>
 </template>
 <script lang="ts">
@@ -9,8 +9,11 @@
 
   import { defineComponent } from 'vue';
 
+  import BasicHelp from './BasicHelp.vue';
+
   export default defineComponent({
-    name: 'BaseTitle',
+    name: 'BasicTitle',
+    components: { BasicHelp },
     props: {
       helpMessage: {
         type: [String, Array] as PropType<string | string[]>,

+ 2 - 0
src/components/Breadcrumb/BreadcrumbItem.vue

@@ -31,10 +31,12 @@
     },
     setup(props) {
       const linkRef = ref<Nullable<HTMLElement>>(null);
+
       const parent = inject('breadcrumb') as {
         separator: string;
         separatorClass: string;
       };
+
       const { push, replace } = useRouter();
 
       onMounted(() => {

+ 40 - 38
src/components/Modal/src/BasicModal.tsx

@@ -1,20 +1,19 @@
 import type { ModalProps, ModalMethods } from './types';
 
+import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue';
+
 import Modal from './Modal';
-import { Button } from 'ant-design-vue';
+import Button from '/@/components/Button/index.vue';
 import ModalWrapper from './ModalWrapper';
 import { BasicTitle } from '/@/components/Basic';
-import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue';
-
 import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from '@ant-design/icons-vue';
 
-import { basicProps } from './props';
-
 import { getSlot, extendSlots } from '/@/utils/helper/tsxHelper';
 import { isFunction } from '/@/utils/is';
 import { deepMerge } from '/@/utils';
 import { buildUUID } from '/@/utils/uuid';
 
+import { basicProps } from './props';
 // import { triggerWindowResize } from '@/utils/event/triggerWindowResizeEvent';
 export default defineComponent({
   name: 'BasicModal',
@@ -22,18 +21,14 @@ export default defineComponent({
   emits: ['visible-change', 'height-change', 'cancel', 'ok', 'register'],
   setup(props, { slots, emit, attrs }) {
     const visibleRef = ref(false);
-
     const propsRef = ref<Partial<ModalProps> | null>(null);
-
     const modalWrapperRef = ref<any>(null);
-
     // modal   Bottom and top height
     const extHeightRef = ref(0);
-
     // Unexpanded height of the popup
     const formerHeightRef = ref(0);
-
     const fullScreenRef = ref(false);
+
     // Custom title component: get title
     const getMergeProps = computed(() => {
       return {
@@ -41,6 +36,7 @@ export default defineComponent({
         ...(unref(propsRef) as any),
       };
     });
+
     // modal component does not need title
     const getProps = computed((): any => {
       const opt = {
@@ -56,9 +52,11 @@ export default defineComponent({
         wrapClassName: className,
       };
     });
+
     watchEffect(() => {
       visibleRef.value = !!props.visible;
     });
+
     watch(
       () => unref(visibleRef),
       (v) => {
@@ -68,6 +66,7 @@ export default defineComponent({
         immediate: false,
       }
     );
+
     /**
      * @description: 渲染标题
      */
@@ -83,13 +82,17 @@ export default defineComponent({
 
     function renderContent() {
       const { useWrapper, loading, wrapperProps } = unref(getProps);
-      return useWrapper ? (
+      if (!useWrapper) return getSlot(slots);
+
+      const showFooter = props.footer !== undefined && !props.footer ? 0 : undefined;
+      return (
         <ModalWrapper
           footerOffset={props.wrapperFooterOffset}
           fullScreen={unref(fullScreenRef)}
           ref={modalWrapperRef}
           loading={loading}
           visible={unref(visibleRef)}
+          modalFooterHeight={showFooter}
           {...wrapperProps}
           onGetExtHeight={(height: number) => {
             extHeightRef.value = height;
@@ -100,13 +103,12 @@ export default defineComponent({
         >
           {() => getSlot(slots)}
         </ModalWrapper>
-      ) : (
-        getSlot(slots)
       );
     }
+
     // 取消事件
     async function handleCancel(e: Event) {
-      e.stopPropagation();
+      e && e.stopPropagation();
       if (props.closeFunc && isFunction(props.closeFunc)) {
         const isClose: boolean = await props.closeFunc();
         visibleRef.value = !isClose;
@@ -115,6 +117,7 @@ export default defineComponent({
       visibleRef.value = false;
       emit('cancel');
     }
+
     // 底部按钮自定义实现,
     function renderFooter() {
       const {
@@ -131,7 +134,6 @@ export default defineComponent({
       return (
         <>
           {getSlot(slots, 'insertFooter')}
-
           {showCancelBtn && (
             <Button {...cancelButtonProps} onClick={handleCancel}>
               {() => cancelText}
@@ -150,11 +152,11 @@ export default defineComponent({
               {() => okText}
             </Button>
           )}
-
           {getSlot(slots, 'appendFooter')}
         </>
       );
     }
+
     /**
      * @description: 关闭按钮
      */
@@ -176,27 +178,26 @@ export default defineComponent({
     }
 
     function handleFullScreen(e: Event) {
-      e.stopPropagation();
+      e && e.stopPropagation();
       fullScreenRef.value = !unref(fullScreenRef);
 
       const modalWrapper = unref(modalWrapperRef);
-      if (modalWrapper) {
-        const modalWrapSpinEl = (modalWrapper.$el as HTMLElement).querySelector(
-          '.ant-spin-nested-loading'
-        );
-        if (modalWrapSpinEl) {
-          if (!unref(formerHeightRef) && unref(fullScreenRef)) {
-            formerHeightRef.value = (modalWrapSpinEl as HTMLElement).offsetHeight;
-            console.log(formerHeightRef);
-          }
-          if (unref(fullScreenRef)) {
-            (modalWrapSpinEl as HTMLElement).style.height = `${
-              window.innerHeight - unref(extHeightRef)
-            }px`;
-          } else {
-            (modalWrapSpinEl as HTMLElement).style.height = `${unref(formerHeightRef)}px`;
-          }
-        }
+      if (!modalWrapper) return;
+
+      const wrapperEl = modalWrapper.$el as HTMLElement;
+      if (!wrapperEl) return;
+
+      const modalWrapSpinEl = wrapperEl.querySelector('.ant-spin-nested-loading') as HTMLElement;
+      if (!modalWrapSpinEl) return;
+
+      if (!unref(formerHeightRef) && unref(fullScreenRef)) {
+        formerHeightRef.value = modalWrapSpinEl.offsetHeight;
+      }
+
+      if (unref(fullScreenRef)) {
+        modalWrapSpinEl.style.height = `${window.innerHeight - unref(extHeightRef)}px`;
+      } else {
+        modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`;
       }
     }
 
@@ -206,21 +207,22 @@ export default defineComponent({
     function setModalProps(props: Partial<ModalProps>): void {
       // Keep the last setModalProps
       propsRef.value = deepMerge(unref(propsRef) || {}, props);
-      if (Reflect.has(props, 'visible')) {
-        visibleRef.value = !!props.visible;
-      }
+      if (!Reflect.has(props, 'visible')) return;
+      visibleRef.value = !!props.visible;
     }
 
     const modalMethods: ModalMethods = {
       setModalProps,
     };
+
     const uuid = buildUUID();
     emit('register', modalMethods, uuid);
+
     return () => (
       <Modal
         onCancel={handleCancel}
-        {...{ ...attrs, ...props, ...unref(getProps) }}
         getContainer={() => document.querySelector('.default-layout__main')}
+        {...{ ...attrs, ...props, ...unref(getProps) }}
       >
         {{
           ...extendSlots(slots, ['default']),

+ 2 - 2
src/components/Modal/src/Modal.tsx

@@ -23,6 +23,7 @@ export default defineComponent({
       dialogHeaderEl.style.cursor = 'move';
 
       dialogHeaderEl.onmousedown = (e: any) => {
+        if (!e) return;
         // 鼠标按下,计算当前元素距离可视区的距离
         const disX = e.clientX;
         const disY = e.clientY;
@@ -84,8 +85,8 @@ export default defineComponent({
     const handleDrag = () => {
       const dragWraps = document.querySelectorAll('.ant-modal-wrap');
       for (const wrap of dragWraps as any) {
+        if (!wrap) continue;
         const display = getStyle(wrap, 'display');
-
         const draggable = wrap.getAttribute('data-drag');
         if (display !== 'none') {
           // 拖拽位置
@@ -98,7 +99,6 @@ export default defineComponent({
       if (!props.visible) {
         return;
       }
-      // context.$nextTick();
       useTimeout(() => {
         handleDrag();
       }, 30);

+ 52 - 57
src/components/Modal/src/ModalWrapper.tsx

@@ -13,10 +13,9 @@ import {
   onUnmounted,
 } from 'vue';
 import { Spin } from 'ant-design-vue';
-import { ScrollContainer } from '/@/components/Container/index';
 
 import { useWindowSizeFn } from '/@/hooks/event/useWindowSize';
-import { useTimeout } from '/@/hooks/core/useTimeout';
+// import { useTimeout } from '/@/hooks/core/useTimeout';
 
 import { getSlot } from '/@/utils/helper/tsxHelper';
 import { useElResize } from '/@/hooks/event/useElResize';
@@ -61,26 +60,46 @@ export default defineComponent({
     const wrapStyle = computed(() => {
       return {
         minHeight: `${props.minHeight}px`,
-        overflow: 'hidden',
+        height: `${unref(realHeightRef)}px`,
+        overflow: 'auto',
       };
     });
 
     // 重试次数
-    let tryCount = 0;
+    // let tryCount = 0;
+    let stopElResizeFn: Fn = () => {};
+
+    watchEffect(() => {
+      setModalHeight();
+    });
+
+    watch(
+      () => props.fullScreen,
+      (v) => {
+        !v && setModalHeight();
+      }
+    );
+
+    onMounted(() => {
+      const { modalHeaderHeight, modalFooterHeight } = props;
+      emit('getExtHeight', modalHeaderHeight + modalFooterHeight);
+      listenElResize();
+    });
+
+    onUnmounted(() => {
+      stopElResizeFn && stopElResizeFn();
+    });
+
+    useWindowSizeFn(setModalHeight);
+
     async function setModalHeight() {
       // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
       // 加上这个,就必须在使用的时候传递父级的visible
-      if (!props.visible) {
-        return;
-      }
+      if (!props.visible) return;
       const wrapperRefDom = unref(wrapperRef);
-      if (!wrapperRefDom) {
-        return;
-      }
+      if (!wrapperRefDom) return;
       const bodyDom = wrapperRefDom.parentElement;
-      if (!bodyDom) {
-        return;
-      }
+      if (!bodyDom) return;
       bodyDom.style.padding = '0';
       await nextTick();
 
@@ -104,23 +123,23 @@ export default defineComponent({
         }
         await nextTick();
         const spinEl = unref(spinRef);
-        if (!spinEl) {
-          useTimeout(() => {
-            // retry
-            if (tryCount < 3) {
-              setModalHeight();
-            }
-            tryCount++;
-          }, 10);
-          return;
-        }
-        tryCount = 0;
+        // if (!spinEl) {
+        //   useTimeout(() => {
+        //     // retry
+        //     if (tryCount < 3) {
+        //       setModalHeight();
+        //     }
+        //     tryCount++;
+        //   }, 10);
+        //   return;
+        // }
+        // tryCount = 0;
 
-        const realHeight = (spinEl.$el.querySelector('.ant-spin-container') as HTMLElement)
-          .scrollHeight;
+        const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement;
+        if (!spinContainerEl) return;
+
+        const realHeight = spinContainerEl.scrollHeight;
 
-        //  16为 p-2和m-2  加起来为4,基础4, 4*4=16
-        // 32 padding
         if (props.fullScreen) {
           realHeightRef.value =
             window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 26;
@@ -138,6 +157,7 @@ export default defineComponent({
         console.log(error);
       }
     }
+
     function listenElResize() {
       const wrapper = unref(wrapperRef);
       if (!wrapper) return;
@@ -146,41 +166,16 @@ export default defineComponent({
       const [start, stop] = useElResize(container, () => {
         setModalHeight();
       });
+      stopElResizeFn = stop;
       start();
-      onUnmounted(() => {
-        stop();
-      });
     }
-    nextTick(() => {});
-    watchEffect(() => {
-      setModalHeight();
-    });
-    watch(
-      () => props.fullScreen,
-      (v) => {
-        !v && setModalHeight();
-      }
-    );
-
-    onMounted(() => {
-      const { modalHeaderHeight, modalFooterHeight } = props;
-      emit('getExtHeight', modalHeaderHeight + modalFooterHeight);
-      listenElResize();
-    });
-
-    useWindowSizeFn(setModalHeight);
 
     return () => {
-      const height = unref(realHeightRef);
       return (
         <div ref={wrapperRef} style={unref(wrapStyle)}>
-          <ScrollContainer>
-            {() => (
-              <Spin ref={spinRef} spinning={props.loading} style={{ height: `${height}px` }}>
-                {() => getSlot(slots)}
-              </Spin>
-            )}
-          </ScrollContainer>
+          <Spin ref={spinRef} spinning={props.loading}>
+            {() => getSlot(slots)}
+          </Spin>
         </div>
       );
     };

+ 1 - 4
src/components/Modal/src/index.less

@@ -26,7 +26,7 @@
     line-height: 16px;
 
     .base-title {
-      cursor: move;
+      cursor: move !important;
     }
   }
 
@@ -56,7 +56,6 @@
   }
 
   .ant-modal-body {
-    // background: #f1f2f6;
     padding: 0;
   }
 
@@ -69,7 +68,6 @@
   }
 
   &-header {
-    // padding: 12.5px 24px;
     padding: 16px;
   }
 
@@ -79,7 +77,6 @@
 
   &-footer {
     padding: 10px 26px 26px 16px;
-    // border-top: none;
 
     button + button {
       margin-left: 10px;

+ 12 - 3
src/components/Modal/src/useModal.ts

@@ -21,15 +21,15 @@ export function useModal(): UseModalReturnType {
   const uidRef = ref<string>('');
   function register(modalMethod: ModalMethods, uuid: string) {
     uidRef.value = uuid;
+
     isProdMode() &&
       onUnmounted(() => {
         modalRef.value = null;
         loadedRef.value = false;
         dataTransferRef[unref(uidRef)] = null;
       });
-    if (unref(loadedRef) && isProdMode() && modalMethod === unref(modalRef)) {
-      return;
-    }
+    if (unref(loadedRef) && isProdMode() && modalMethod === unref(modalRef)) return;
+
     modalRef.value = modalMethod;
   }
   const getInstance = () => {
@@ -44,11 +44,13 @@ export function useModal(): UseModalReturnType {
     setModalProps: (props: Partial<ModalProps>): void => {
       getInstance().setModalProps(props);
     },
+
     openModal: (visible = true): void => {
       getInstance().setModalProps({
         visible: visible,
       });
     },
+
     transferModalData(val: any) {
       dataTransferRef[unref(uidRef)] = val;
     },
@@ -64,6 +66,7 @@ export const useModalInner = (): UseModalInnerReturnType => {
   if (!currentInstall) {
     throw new Error('instance is undefined!');
   }
+
   const getInstance = () => {
     const instance = unref(modalInstanceRef);
     if (!instance) {
@@ -71,26 +74,32 @@ export const useModalInner = (): UseModalInnerReturnType => {
     }
     return instance;
   };
+
   const register = (modalInstance: ModalMethods, uuid: string) => {
     uidRef.value = uuid;
     modalInstanceRef.value = modalInstance;
     currentInstall.emit('register', modalInstance);
   };
+
   return [
     register,
     {
       receiveModalDataRef: computed(() => {
         return dataTransferRef[unref(uidRef)];
       }),
+
       changeLoading: (loading = true) => {
         getInstance().setModalProps({ loading });
       },
+
       changeOkLoading: (loading = true) => {
         getInstance().setModalProps({ confirmLoading: loading });
       },
+
       closeModal: () => {
         getInstance().setModalProps({ visible: false });
       },
+
       setModalProps: (props: Partial<ModalProps>) => {
         getInstance().setModalProps(props);
       },

+ 1 - 2
src/components/registerGlobComp.ts

@@ -1,10 +1,9 @@
 import Icon from './Icon/index';
-import { BasicHelp, BasicTitle } from './Basic';
 import Button from './Button/index.vue';
 import { Button as AntButton } from 'ant-design-vue';
 import { getApp } from '/@/useApp';
 
-const compList = [Icon, BasicHelp, BasicTitle, Button, AntButton.Group];
+const compList = [Icon, Button, AntButton.Group];
 
 // Fix hmr multiple registered components
 let registered = false;