From fb0c7763eddde38d3746cb424ebe9662ac576c86 Mon Sep 17 00:00:00 2001 From: vben <anncwb@126.com> Date: Thu, 29 Oct 2020 23:59:54 +0800 Subject: [PATCH] fix(modal): fix modal not showing footer --- CHANGELOG.zh_CN.md | 7 +++++++ src/components/Authority/src/index.vue | 3 ++- src/components/Basic/src/BasicArrow.vue | 4 +--- src/components/Basic/src/BasicHelp.vue | 8 +++++--- src/components/Basic/src/BasicTitle.vue | 7 +++++-- src/components/Breadcrumb/BreadcrumbItem.vue | 2 ++ src/components/Modal/src/BasicModal.tsx | 78 ++++++++++++++++++++++++++++++++++++++++-------------------------------------- src/components/Modal/src/Modal.tsx | 4 ++-- src/components/Modal/src/ModalWrapper.tsx | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------- src/components/Modal/src/index.less | 5 +---- src/components/Modal/src/useModal.ts | 15 ++++++++++++--- src/components/registerGlobComp.ts | 3 +-- 12 files changed, 130 insertions(+), 115 deletions(-) diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index bd457f7..84d4187 100644 --- a/CHANGELOG.zh_CN.md +++ b/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) diff --git a/src/components/Authority/src/index.vue b/src/components/Authority/src/index.vue index 7dfd138..f9f4735 100644 --- a/src/components/Authority/src/index.vue +++ b/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'; diff --git a/src/components/Basic/src/BasicArrow.vue b/src/components/Basic/src/BasicArrow.vue index 799b250..41ceb8c 100644 --- a/src/components/Basic/src/BasicArrow.vue +++ b/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; }); diff --git a/src/components/Basic/src/BasicHelp.vue b/src/components/Basic/src/BasicHelp.vue index 15c527f..f2189ac 100644 --- a/src/components/Basic/src/BasicHelp.vue +++ b/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, diff --git a/src/components/Basic/src/BasicTitle.vue b/src/components/Basic/src/BasicTitle.vue index 108f65f..4a8573e 100644 --- a/src/components/Basic/src/BasicTitle.vue +++ b/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[]>, diff --git a/src/components/Breadcrumb/BreadcrumbItem.vue b/src/components/Breadcrumb/BreadcrumbItem.vue index 61a8b69..e325c57 100644 --- a/src/components/Breadcrumb/BreadcrumbItem.vue +++ b/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(() => { diff --git a/src/components/Modal/src/BasicModal.tsx b/src/components/Modal/src/BasicModal.tsx index 0be402a..6222443 100644 --- a/src/components/Modal/src/BasicModal.tsx +++ b/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']), diff --git a/src/components/Modal/src/Modal.tsx b/src/components/Modal/src/Modal.tsx index 379c4a3..fa92205 100644 --- a/src/components/Modal/src/Modal.tsx +++ b/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); diff --git a/src/components/Modal/src/ModalWrapper.tsx b/src/components/Modal/src/ModalWrapper.tsx index 818b4cc..6a945a4 100644 --- a/src/components/Modal/src/ModalWrapper.tsx +++ b/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> ); }; diff --git a/src/components/Modal/src/index.less b/src/components/Modal/src/index.less index f44e1be..12a6bcb 100644 --- a/src/components/Modal/src/index.less +++ b/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; diff --git a/src/components/Modal/src/useModal.ts b/src/components/Modal/src/useModal.ts index 0411223..b008a36 100644 --- a/src/components/Modal/src/useModal.ts +++ b/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); }, diff --git a/src/components/registerGlobComp.ts b/src/components/registerGlobComp.ts index e0561e0..5fe283c 100644 --- a/src/components/registerGlobComp.ts +++ b/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; -- libgit2 0.23.3