diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index 2f588cadad786db95ddf551c37981a4637a5af30..60f977cd951233431ca9984d18344905ade3f35a 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -18,12 +18,18 @@ - 缓存可以配置是否加密,默认生产环境开启 Aes 加密 - 新增标签页拖拽排序 +- 新增 LayoutFooter.默认显示,可以在配置内关闭 + +### ⚡ Performance Improvements + +- 优化`Modal`组件全屏动画不流畅问题 ### 🐛 Bug Fixes - 修复 tree 文本超出挡住操作按钮问题 - 修复通过 useRedo 刷新页面参数丢失问题 - 修复表单校验先设置在校验及控制台错误信息问题 +- 修复`modal`与`drawer`组件传递数组参数问题 ### 🎫 Chores diff --git a/src/components/Drawer/index.ts b/src/components/Drawer/index.ts index b3884399c2e915a76581bde7d9a47c848a809e52..4fa33a442dd74163a81de567820bd4304d8add28 100644 --- a/src/components/Drawer/index.ts +++ b/src/components/Drawer/index.ts @@ -1,4 +1,6 @@ -export { default as BasicDrawer } from './src/BasicDrawer'; +import BasicDrawerLib from './src/BasicDrawer'; +import { withInstall } from '../util'; -export { useDrawer, useDrawerInner } from './src/useDrawer'; export * from './src/types'; +export { useDrawer, useDrawerInner } from './src/useDrawer'; +export const BasicDrawer = withInstall(BasicDrawerLib); diff --git a/src/components/Drawer/src/BasicDrawer.tsx b/src/components/Drawer/src/BasicDrawer.tsx index b03304f01eaecd0670a1c55f2bb7dc4f756cfef0..3736bb7acc7b031d469bcef3287267c62db00377 100644 --- a/src/components/Drawer/src/BasicDrawer.tsx +++ b/src/components/Drawer/src/BasicDrawer.tsx @@ -1,6 +1,7 @@ import './index.less'; import type { DrawerInstance, DrawerProps } from './types'; +import type { CSSProperties } from 'vue'; import { defineComponent, ref, computed, watchEffect, watch, unref, nextTick, toRaw } from 'vue'; import { Drawer, Row, Col, Button } from 'ant-design-vue'; @@ -9,53 +10,96 @@ import { BasicTitle } from '/@/components/Basic'; import { FullLoading } from '/@/components/Loading/index'; import { LeftOutlined } from '@ant-design/icons-vue'; -import { basicProps } from './props'; +import { useI18n } from '/@/hooks/web/useI18n'; import { getSlot } from '/@/utils/helper/tsxHelper'; import { isFunction, isNumber } from '/@/utils/is'; -import { buildUUID } from '/@/utils/uuid'; import { deepMerge } from '/@/utils'; -import { useI18n } from '/@/hooks/web/useI18n'; +import { tryTsxEmit } from '/@/utils/helper/vueHelper'; + +import { basicProps } from './props'; const prefixCls = 'basic-drawer'; export default defineComponent({ - // inheritAttrs: false, + inheritAttrs: false, props: basicProps, emits: ['visible-change', 'ok', 'close', 'register'], setup(props, { slots, emit, attrs }) { const scrollRef = ref(null); - const visibleRef = ref(false); - const propsRef = ref | null>(null); + const propsRef = ref>>(null); const { t } = useI18n('component.drawer'); - const getMergeProps = computed((): any => { - return deepMerge(toRaw(props), unref(propsRef)); - }); - - const getProps = computed(() => { - const opt: any = { - placement: 'right', - ...attrs, - ...props, - ...(unref(propsRef) as any), - visible: unref(visibleRef), - }; - opt.title = undefined; + const getMergeProps = computed( + (): DrawerProps => { + return deepMerge(toRaw(props), unref(propsRef)); + } + ); - if (opt.isDetail) { - if (!opt.width) { - opt.width = '100%'; - } - opt.wrapClassName = opt.wrapClassName - ? `${opt.wrapClassName} ${prefixCls}__detail` - : `${prefixCls}__detail`; - if (!opt.getContainer) { - opt.getContainer = '.layout-content'; + const getProps = computed( + (): DrawerProps => { + const opt = { + placement: 'right', + ...attrs, + ...unref(getMergeProps), + visible: unref(visibleRef), + }; + opt.title = undefined; + const { isDetail, width, wrapClassName, getContainer } = opt; + if (isDetail) { + if (!width) { + opt.width = '100%'; + } + const detailCls = `${prefixCls}__detail`; + + opt.wrapClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls; + + if (!getContainer) { + // TODO type error? + opt.getContainer = '.layout-content' as any; + } } + return opt as DrawerProps; } - return opt; + ); + + const getBindValues = computed( + (): DrawerProps => { + return { + ...attrs, + ...unref(getProps), + }; + } + ); + + // Custom implementation of the bottom button, + const getFooterHeight = computed(() => { + const { footerHeight, showFooter } = unref(getProps); + + if (showFooter && footerHeight) { + return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`; + } + return `0px`; + }); + + const getScrollContentStyle = computed( + (): CSSProperties => { + const footerHeight = unref(getFooterHeight); + return { + position: 'relative', + height: `calc(100% - ${footerHeight})`, + overflow: 'auto', + padding: '16px', + paddingBottom: '30px', + }; + } + ); + + const getLoading = computed(() => { + return { + hidden: !unref(getProps).loading, + }; }); watchEffect(() => { @@ -74,22 +118,13 @@ export default defineComponent({ } ); - // Custom implementation of the bottom button, - const getFooterHeight = computed(() => { - const { footerHeight, showFooter }: DrawerProps = unref(getProps); - if (showFooter && footerHeight) { - return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`; - } - return `0px`; - }); - // Cancel event - async function onClose(e: any) { + async function onClose(e: ChangeEvent) { const { closeFunc } = unref(getProps); emit('close', e); if (closeFunc && isFunction(closeFunc)) { const res = await closeFunc(); - res && (visibleRef.value = false); + visibleRef.value = !res; return; } visibleRef.value = false; @@ -98,12 +133,16 @@ export default defineComponent({ function setDrawerProps(props: Partial): void { // Keep the last setDrawerProps propsRef.value = deepMerge(unref(propsRef) || {}, props); + if (Reflect.has(props, 'visible')) { visibleRef.value = !!props.visible; } } function renderFooter() { + if (slots?.footer) { + return getSlot(slots, 'footer'); + } const { showCancelBtn, cancelButtonProps, @@ -114,65 +153,64 @@ export default defineComponent({ okButtonProps, confirmLoading, showFooter, - }: DrawerProps = unref(getProps); + } = unref(getProps); + if (!showFooter) { + return null; + } return ( - getSlot(slots, 'footer') || - (showFooter && ( -
- {getSlot(slots, 'insertFooter')} - - {showCancelBtn && ( - - )} - {getSlot(slots, 'centerFooter')} - {showOkBtn && ( - - )} - - {getSlot(slots, 'appendFooter')} -
- )) +
+ {getSlot(slots, 'insertFooter')} + {showCancelBtn && ( + + )} + {getSlot(slots, 'centerFooter')} + {showOkBtn && ( + + )} + {getSlot(slots, 'appendFooter')} +
); } function renderHeader() { + if (slots?.title) { + return getSlot(slots, 'title'); + } const { title } = unref(getMergeProps); - return props.isDetail ? ( - getSlot(slots, 'title') || ( - - {() => ( - <> - {props.showDetailBack && ( - - )} - - {title && ( - - {() => title} - - )} - - {getSlot(slots, 'titleToolbar')} - - )} - - ) - ) : ( - {() => title || getSlot(slots, 'title')} + + if (!props.isDetail) { + return {() => title || getSlot(slots, 'title')}; + } + return ( + + {() => ( + <> + {props.showDetailBack && ( + + )} + {title && ( + + {() => title} + + )} + {getSlot(slots, 'titleToolbar')} + + )} + ); } @@ -180,41 +218,20 @@ export default defineComponent({ setDrawerProps: setDrawerProps, }; - const uuid = buildUUID(); - emit('register', drawerInstance, uuid); + tryTsxEmit((instance) => { + emit('register', drawerInstance, instance.uid); + }); return () => { - const footerHeight = unref(getFooterHeight); return ( - + {{ title: () => renderHeader(), default: () => ( <> -
- - {getSlot(slots, 'default')} +
+ + {getSlot(slots)}
{renderFooter()} diff --git a/src/components/Drawer/src/props.ts b/src/components/Drawer/src/props.ts index 19481bc5bd725c7c34908c61e19d64ec95e223ef..aa64607b30c92473693fb13074b5e483df304eb0 100644 --- a/src/components/Drawer/src/props.ts +++ b/src/components/Drawer/src/props.ts @@ -1,72 +1,37 @@ import type { PropType } from 'vue'; import { useI18n } from '/@/hooks/web/useI18n'; +import { propTypes } from '/@/utils/propTypes'; const { t } = useI18n('component.drawer'); export const footerProps = { - confirmLoading: Boolean as PropType, + confirmLoading: propTypes.bool, /** * @description: Show close button */ - showCancelBtn: { - type: Boolean as PropType, - default: true, - }, + showCancelBtn: propTypes.bool.def(true), cancelButtonProps: Object as PropType, - cancelText: { - type: String as PropType, - default: t('cancelText'), - }, + cancelText: propTypes.string.def(t('cancelText')), /** * @description: Show confirmation button */ - showOkBtn: { - type: Boolean as PropType, - default: true, - }, - okButtonProps: Object as PropType, - okText: { - type: String as PropType, - default: t('okText'), - }, - okType: { - type: String as PropType, - default: 'primary', - }, - showFooter: { - type: Boolean as PropType, - default: false, - }, + showOkBtn: propTypes.bool.def(true), + okButtonProps: propTypes.any, + okText: propTypes.string.def(t('okText')), + okType: propTypes.string.def('primary'), + showFooter: propTypes.bool, footerHeight: { type: [String, Number] as PropType, default: 60, }, }; export const basicProps = { - isDetail: { - type: Boolean as PropType, - default: false, - }, - title: { - type: String as PropType, - default: '', - }, - showDetailBack: { - type: Boolean as PropType, - default: true, - }, - visible: { - type: Boolean as PropType, - default: false, - }, - loading: { - type: Boolean as PropType, - default: false, - }, - maskClosable: { - type: Boolean as PropType, - default: true, - }, + isDetail: propTypes.bool, + title: propTypes.string.def(''), + showDetailBack: propTypes.bool.def(true), + visible: propTypes.bool, + loading: propTypes.bool, + maskClosable: propTypes.bool.def(true), getContainer: { type: [Object, String] as PropType, }, @@ -78,10 +43,7 @@ export const basicProps = { type: [Function, Object] as PropType, default: null, }, - triggerWindowResize: { - type: Boolean as PropType, - default: false, - }, - destroyOnClose: Boolean as PropType, + triggerWindowResize: propTypes.bool, + destroyOnClose: propTypes.bool, ...footerProps, }; diff --git a/src/components/Drawer/src/types.ts b/src/components/Drawer/src/types.ts index 71d22ab20bce69972a7619fb020bcc0a547ff02d..78e4cfdb3978f5b7cd826154173ddba944031e4b 100644 --- a/src/components/Drawer/src/types.ts +++ b/src/components/Drawer/src/types.ts @@ -75,7 +75,7 @@ export interface DrawerProps extends DrawerFooterProps { * @type ScrollContainerOptions */ scrollOptions?: ScrollContainerOptions; - closeFunc?: () => Promise; + closeFunc?: () => Promise; triggerWindowResize?: boolean; /** * Whether a close (x) button is visible on top right of the Drawer dialog or not. diff --git a/src/components/Drawer/src/useDrawer.ts b/src/components/Drawer/src/useDrawer.ts index b081356d72d3b078a652776e2b399a964e84967e..de7719f0398b0bb0d64e8914bd49d5ee5621c5f2 100644 --- a/src/components/Drawer/src/useDrawer.ts +++ b/src/components/Drawer/src/useDrawer.ts @@ -6,12 +6,15 @@ import type { UseDrawerInnerReturnType, } from './types'; -import { ref, getCurrentInstance, onUnmounted, unref, reactive, watchEffect, nextTick } from 'vue'; +import { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw } from 'vue'; import { isProdMode } from '/@/utils/env'; import { isFunction } from '/@/utils/is'; +import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; +import { isEqual } from 'lodash-es'; const dataTransferRef = reactive({}); + /** * @description: Applicable to separate drawer and call outside */ @@ -19,21 +22,23 @@ export function useDrawer(): UseDrawerReturnType { if (!getCurrentInstance()) { throw new Error('Please put useDrawer function in the setup function!'); } + const drawerRef = ref(null); - const loadedRef = ref(false); + const loadedRef = ref>(false); const uidRef = ref(''); - function getDrawer(drawerInstance: DrawerInstance, uuid: string) { - uidRef.value = uuid; + function register(drawerInstance: DrawerInstance, uuid: string) { isProdMode() && - onUnmounted(() => { + tryOnUnmounted(() => { drawerRef.value = null; loadedRef.value = null; dataTransferRef[unref(uidRef)] = null; }); + if (unref(loadedRef) && isProdMode() && drawerInstance === unref(drawerRef)) { return; } + uidRef.value = uuid; drawerRef.value = drawerInstance; loadedRef.value = true; } @@ -55,37 +60,46 @@ export function useDrawer(): UseDrawerReturnType { getInstance().setDrawerProps({ visible: visible, }); - if (data) { - dataTransferRef[unref(uidRef)] = openOnSet - ? { - ...data, - __t__: Date.now(), - } - : data; + if (!data) return; + + if (openOnSet) { + dataTransferRef[unref(uidRef)] = null; + dataTransferRef[unref(uidRef)] = data; + return; + } + const equal = isEqual(toRaw(dataTransferRef[unref(uidRef)]), data); + if (!equal) { + dataTransferRef[unref(uidRef)] = data; } }, }; - return [getDrawer, methods]; + return [register, methods]; } + export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => { - const drawerInstanceRef = ref(null); + const drawerInstanceRef = ref>(null); const currentInstall = getCurrentInstance(); const uidRef = ref(''); if (!currentInstall) { - throw new Error('instance is undefined!'); + throw new Error('useDrawerInner instance is undefined!'); } const getInstance = () => { const instance = unref(drawerInstanceRef); if (!instance) { - throw new Error('instance is undefined!'); + throw new Error('useDrawerInner instance is undefined!'); } return instance; }; const register = (modalInstance: DrawerInstance, uuid: string) => { + isProdMode() && + tryOnUnmounted(() => { + drawerInstanceRef.value = null; + }); + uidRef.value = uuid; drawerInstanceRef.value = modalInstance; currentInstall.emit('register', modalInstance); diff --git a/src/components/Modal/index.ts b/src/components/Modal/index.ts index aa6cdc005ff3c8597a367dc2f4108975b5a711c9..aecdf90148aa5bf689f1cb3b0724a88f6691e216 100644 --- a/src/components/Modal/index.ts +++ b/src/components/Modal/index.ts @@ -1,5 +1,8 @@ import './src/index.less'; -export { default as BasicModal } from './src/BasicModal'; -export { default as Modal } from './src/Modal'; +import BasicModalLib from './src/BasicModal'; +import { withInstall } from '../util'; + +export { useModalContext } from './src/useModalContext'; export { useModal, useModalInner } from './src/useModal'; export * from './src/types'; +export const BasicModal = withInstall(BasicModalLib); diff --git a/src/components/Modal/src/BasicModal.tsx b/src/components/Modal/src/BasicModal.tsx index 2ef49b3915414e0899fa8954e4e0a448ee028cdd..3f55a76547fb0c69d08d0f85602701b8035b1479 100644 --- a/src/components/Modal/src/BasicModal.tsx +++ b/src/components/Modal/src/BasicModal.tsx @@ -1,6 +1,6 @@ import type { ModalProps, ModalMethods } from './types'; -import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; +import { defineComponent, computed, ref, watch, unref, watchEffect, toRef } from 'vue'; import Modal from './Modal'; import { Button } from '/@/components/Button'; @@ -11,10 +11,10 @@ import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from '@ant- import { getSlot, extendSlots } from '/@/utils/helper/tsxHelper'; import { isFunction } from '/@/utils/is'; import { deepMerge } from '/@/utils'; -import { buildUUID } from '/@/utils/uuid'; +import { tryTsxEmit } from '/@/utils/helper/vueHelper'; import { basicProps } from './props'; -// import { triggerWindowResize } from '@/utils/event/triggerWindowResizeEvent'; +import { useFullScreen } from './useFullScreen'; export default defineComponent({ name: 'BasicModal', props: basicProps, @@ -26,31 +26,41 @@ export default defineComponent({ // 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 { - ...props, - ...(unref(propsRef) as any), - }; + const getMergeProps = computed( + (): ModalProps => { + return { + ...props, + ...(unref(propsRef) as any), + }; + } + ); + + const { handleFullScreen, getWrapClassName, fullScreenRef } = useFullScreen({ + modalWrapperRef, + extHeightRef, + wrapClassName: toRef(getMergeProps.value, 'wrapClassName'), }); // modal component does not need title - const getProps = computed((): any => { - const opt = { - ...props, - ...((unref(propsRef) || {}) as any), - visible: unref(visibleRef), - title: undefined, - }; - const { wrapClassName = '' } = opt; - const className = unref(fullScreenRef) ? `${wrapClassName} fullscreen-modal` : wrapClassName; - return { - ...opt, - wrapClassName: className, - }; + const getProps = computed( + (): ModalProps => { + const opt = { + ...unref(getMergeProps), + visible: unref(visibleRef), + title: undefined, + }; + + return { + ...opt, + wrapClassName: unref(getWrapClassName), + }; + } + ); + + const getModalBindValue = computed((): any => { + return { ...attrs, ...unref(getProps) }; }); watchEffect(() => { @@ -80,7 +90,35 @@ export default defineComponent({ ); } + // 取消事件 + async function handleCancel(e: Event) { + e?.stopPropagation(); + + if (props.closeFunc && isFunction(props.closeFunc)) { + const isClose: boolean = await props.closeFunc(); + visibleRef.value = !isClose; + return; + } + + visibleRef.value = false; + emit('cancel'); + } + + /** + * @description: 设置modal参数 + */ + function setModalProps(props: Partial): void { + // Keep the last setModalProps + propsRef.value = deepMerge(unref(propsRef) || {}, props); + if (!Reflect.has(props, 'visible')) return; + visibleRef.value = !!props.visible; + } + function renderContent() { + type OmitWrapperType = Omit< + ModalProps, + 'fullScreen' | 'modalFooterHeight' | 'visible' | 'loading' + >; const { useWrapper, loading, wrapperProps } = unref(getProps); if (!useWrapper) return getSlot(slots); @@ -93,7 +131,7 @@ export default defineComponent({ loading={loading} visible={unref(visibleRef)} modalFooterHeight={showFooter} - {...wrapperProps} + {...((wrapperProps as unknown) as OmitWrapperType)} onGetExtHeight={(height: number) => { extHeightRef.value = height; }} @@ -106,18 +144,6 @@ export default defineComponent({ ); } - // 取消事件 - async function handleCancel(e: Event) { - e && e.stopPropagation(); - if (props.closeFunc && isFunction(props.closeFunc)) { - const isClose: boolean = await props.closeFunc(); - visibleRef.value = !isClose; - return; - } - visibleRef.value = false; - emit('cancel'); - } - // 底部按钮自定义实现, function renderFooter() { const { @@ -162,64 +188,37 @@ export default defineComponent({ */ function renderClose() { const { canFullscreen } = unref(getProps); - if (!canFullscreen) { - return null; - } + + const fullScreen = unref(fullScreenRef) ? ( + + ) : ( + + ); + + const cls = [ + 'custom-close-icon', + { + 'can-full': canFullscreen, + }, + ]; + return ( -
- {unref(fullScreenRef) ? ( - - ) : ( - - )} +
+ {canFullscreen && fullScreen}
); } - function handleFullScreen(e: Event) { - e && e.stopPropagation(); - fullScreenRef.value = !unref(fullScreenRef); - - const modalWrapper = unref(modalWrapperRef); - 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`; - } - } - - /** - * @description: 设置modal参数 - */ - function setModalProps(props: Partial): void { - // Keep the last setModalProps - propsRef.value = deepMerge(unref(propsRef) || {}, props); - if (!Reflect.has(props, 'visible')) return; - visibleRef.value = !!props.visible; - } - const modalMethods: ModalMethods = { setModalProps, }; - const uuid = buildUUID(); - emit('register', modalMethods, uuid); - + tryTsxEmit((instance) => { + emit('register', modalMethods, instance.uid); + }); return () => ( - + {{ footer: () => renderFooter(), closeIcon: () => renderClose(), diff --git a/src/components/Modal/src/Modal.tsx b/src/components/Modal/src/Modal.tsx index 6b36493d84a9e52032edf69a07e20684b0261b14..abbdb321bf68cd509d2c2f0d193fc0936279be2e 100644 --- a/src/components/Modal/src/Modal.tsx +++ b/src/components/Modal/src/Modal.tsx @@ -1,7 +1,7 @@ import { Modal } from 'ant-design-vue'; -import { defineComponent, watchEffect } from 'vue'; +import { defineComponent, toRefs } from 'vue'; import { basicProps } from './props'; -import { useTimeoutFn } from '/@/hooks/core/useTimeout'; +import { useModalDragMove } from './useModalDrag'; import { extendSlots } from '/@/utils/helper/tsxHelper'; export default defineComponent({ @@ -9,99 +9,12 @@ export default defineComponent({ inheritAttrs: false, props: basicProps, setup(props, { attrs, slots }) { - const getStyle = (dom: any, attr: any) => { - return getComputedStyle(dom)[attr]; - }; - const drag = (wrap: any) => { - if (!wrap) return; - wrap.setAttribute('data-drag', props.draggable); - const dialogHeaderEl = wrap.querySelector('.ant-modal-header'); - const dragDom = wrap.querySelector('.ant-modal'); - - if (!dialogHeaderEl || !dragDom || !props.draggable) return; - - dialogHeaderEl.style.cursor = 'move'; - - dialogHeaderEl.onmousedown = (e: any) => { - if (!e) return; - // 鼠标按下,计算当前元素距离可视区的距离 - const disX = e.clientX; - const disY = e.clientY; - const screenWidth = document.body.clientWidth; // body当前宽度 - const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) - - const dragDomWidth = dragDom.offsetWidth; // 对话框宽度 - const dragDomheight = dragDom.offsetHeight; // 对话框高度 - - const minDragDomLeft = dragDom.offsetLeft; - - const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; - const minDragDomTop = dragDom.offsetTop; - const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; - // 获取到的值带px 正则匹配替换 - const domLeft = getStyle(dragDom, 'left'); - const domTop = getStyle(dragDom, 'top'); - let styL = +domLeft; - let styT = +domTop; - - // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px - if (domLeft.includes('%')) { - styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100); - styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100); - } else { - styL = +domLeft.replace(/px/g, ''); - styT = +domTop.replace(/px/g, ''); - } - - document.onmousemove = function (e) { - // 通过事件委托,计算移动的距离 - let left = e.clientX - disX; - let top = e.clientY - disY; - - // 边界处理 - if (-left > minDragDomLeft) { - left = -minDragDomLeft; - } else if (left > maxDragDomLeft) { - left = maxDragDomLeft; - } - - if (-top > minDragDomTop) { - top = -minDragDomTop; - } else if (top > maxDragDomTop) { - top = maxDragDomTop; - } - - // 移动当前元素 - dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; - }; - - document.onmouseup = () => { - document.onmousemove = null; - document.onmouseup = null; - }; - }; - }; - - 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') { - // 拖拽位置 - (draggable === null || props.destroyOnClose) && drag(wrap); - } - } - }; + const { visible, draggable, destroyOnClose } = toRefs(props); - watchEffect(() => { - if (!props.visible) { - return; - } - useTimeoutFn(() => { - handleDrag(); - }, 30); + useModalDragMove({ + visible, + destroyOnClose, + draggable, }); return () => { diff --git a/src/components/Modal/src/ModalWrapper.tsx b/src/components/Modal/src/ModalWrapper.tsx index 5df0dd70069b8744d8b5da7cf945659372a9273d..8ee539c3864dbd2c6ffa118a3742d2cb1197e48e 100644 --- a/src/components/Modal/src/ModalWrapper.tsx +++ b/src/components/Modal/src/ModalWrapper.tsx @@ -1,5 +1,5 @@ -import type { PropType } from 'vue'; import type { ModalWrapperProps } from './types'; +import type { CSSProperties } from 'vue'; import { defineComponent, @@ -18,59 +18,44 @@ import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; import { getSlot } from '/@/utils/helper/tsxHelper'; import { useElResize } from '/@/hooks/event/useElResize'; -import { provideModal } from './provideModal'; +import { propTypes } from '/@/utils/propTypes'; +import { createModalContext } from './useModalContext'; export default defineComponent({ name: 'ModalWrapper', props: { - loading: { - type: Boolean as PropType, - default: false, - }, - modalHeaderHeight: { - type: Number as PropType, - default: 50, - }, - modalFooterHeight: { - type: Number as PropType, - default: 70, - }, - minHeight: { - type: Number as PropType, - default: 200, - }, - footerOffset: { - type: Number as PropType, - default: 0, - }, - visible: { - type: Boolean as PropType, - default: false, - }, - fullScreen: { - type: Boolean as PropType, - default: false, - }, + loading: propTypes.bool, + modalHeaderHeight: propTypes.number.def(50), + modalFooterHeight: propTypes.number.def(54), + minHeight: propTypes.number.def(200), + footerOffset: propTypes.number.def(0), + visible: propTypes.bool, + fullScreen: propTypes.bool, }, emits: ['heightChange', 'getExtHeight'], setup(props: ModalWrapperProps, { slots, emit }) { - const wrapperRef = ref(null); + const wrapperRef = ref(null); const spinRef = ref(null); const realHeightRef = ref(0); - // 重试次数 - // let tryCount = 0; + let stopElResizeFn: Fn = () => {}; - provideModal(setModalHeight); + useWindowSizeFn(setModalHeight); - const wrapStyle = computed(() => { - return { - minHeight: `${props.minHeight}px`, - height: `${unref(realHeightRef)}px`, - overflow: 'auto', - }; + createModalContext({ + redoModalHeight: setModalHeight, }); + const wrapStyle = computed( + (): CSSProperties => { + return { + minHeight: `${props.minHeight}px`, + height: `${unref(realHeightRef)}px`, + overflow: 'auto', + }; + } + ); + watchEffect(() => { setModalHeight(); }); @@ -92,8 +77,6 @@ export default defineComponent({ stopElResizeFn && stopElResizeFn(); }); - useWindowSizeFn(setModalHeight); - async function setModalHeight() { // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度 // 加上这个,就必须在使用的时候传递父级的visible @@ -107,9 +90,8 @@ export default defineComponent({ try { const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement; - if (!modalDom) { - return; - } + if (!modalDom) return; + const modalRect = getComputedStyle(modalDom).top; const modalTop = Number.parseInt(modalRect); let maxHeight = @@ -135,11 +117,12 @@ export default defineComponent({ if (props.fullScreen) { realHeightRef.value = - window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 6; + window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight; } else { realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30; } emit('heightChange', unref(realHeightRef)); + nextTick(() => { const el = spinEl.$el; if (el) { @@ -154,8 +137,10 @@ export default defineComponent({ function listenElResize() { const wrapper = unref(wrapperRef); if (!wrapper) return; + const container = wrapper.querySelector('.ant-spin-container'); if (!container) return; + const [start, stop] = useElResize(container, () => { setModalHeight(); }); diff --git a/src/components/Modal/src/index.less b/src/components/Modal/src/index.less index 12a6bcb0ba2acdb85016f499d2befdd0eb7f1dca..48b73f5bb6f2ebd88f0eeac25da79c4cf8ebe49e 100644 --- a/src/components/Modal/src/index.less +++ b/src/components/Modal/src/index.less @@ -9,6 +9,11 @@ bottom: 0 !important; left: 0 !important; width: 100% !important; + height: 100%; + + &-content { + height: 100%; + } } } @@ -35,8 +40,23 @@ height: 95%; align-items: center; - > * { - margin-left: 12px; + > span { + margin-left: 48px; + font-size: 16px; + } + + &.can-full { + > span { + margin-left: 12px; + } + } + + &:not(.can-full) { + > span:nth-child(1) { + &:hover { + font-weight: 700; + } + } } & span:nth-child(1) { @@ -76,7 +96,7 @@ } &-footer { - padding: 10px 26px 26px 16px; + // padding: 10px 26px 26px 16px; button + button { margin-left: 10px; diff --git a/src/components/Modal/src/props.ts b/src/components/Modal/src/props.ts index 3199712dba37fa8ccb8e78541dba5ad902c9ee17..60cf0871eec85c94f3244efd5d9d5a097d880760 100644 --- a/src/components/Modal/src/props.ts +++ b/src/components/Modal/src/props.ts @@ -2,66 +2,38 @@ import type { PropType } from 'vue'; import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; import { useI18n } from '/@/hooks/web/useI18n'; +import { propTypes } from '/@/utils/propTypes'; const { t } = useI18n('component.modal'); export const modalProps = { - visible: Boolean as PropType, + visible: propTypes.bool, // open drag - draggable: { - type: Boolean as PropType, - default: true, - }, - centered: { - type: Boolean as PropType, - default: false, - }, - cancelText: { - type: String as PropType, - default: t('cancelText'), - }, - okText: { - type: String as PropType, - default: t('okText'), - }, + draggable: propTypes.bool.def(true), + centered: propTypes.bool, + cancelText: propTypes.string.def(t('cancelText')), + okText: propTypes.string.def(t('okText')), + closeFunc: Function as PropType<() => Promise>, }; export const basicProps = Object.assign({}, modalProps, { // Can it be full screen - canFullscreen: { - type: Boolean as PropType, - default: true, - }, + canFullscreen: propTypes.bool.def(true), // After enabling the wrapper, the bottom can be increased in height - wrapperFooterOffset: { - type: Number as PropType, - default: 0, - }, + wrapperFooterOffset: propTypes.number.def(0), // Warm reminder message helpMessage: [String, Array] as PropType, // Whether to setting wrapper - useWrapper: { - type: Boolean as PropType, - default: true, - }, - loading: { - type: Boolean as PropType, - default: false, - }, + useWrapper: propTypes.bool.def(true), + loading: propTypes.bool, /** * @description: Show close button */ - showCancelBtn: { - type: Boolean as PropType, - default: true, - }, + showCancelBtn: propTypes.bool.def(true), /** * @description: Show confirmation button */ - showOkBtn: { - type: Boolean as PropType, - default: true, - }, + showOkBtn: propTypes.bool.def(true), wrapperProps: Object as PropType, diff --git a/src/components/Modal/src/provideModal.ts b/src/components/Modal/src/provideModal.ts deleted file mode 100644 index 6c24b8ccb64583311e85290316e57120bea885b0..0000000000000000000000000000000000000000 --- a/src/components/Modal/src/provideModal.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { provide, inject } from 'vue'; - -const key = Symbol('basic-modal'); - -export function provideModal(redoHeight: Fn) { - provide(key, redoHeight); -} - -export function injectModal(): Fn { - return inject(key, () => {}) as Fn; -} diff --git a/src/components/Modal/src/types.ts b/src/components/Modal/src/types.ts index ad3ec53b8fb6fc7e13722d7091b2f830631b9218..cfcac4c14182cd8130ee7e65c2a3eabb59df4893 100644 --- a/src/components/Modal/src/types.ts +++ b/src/components/Modal/src/types.ts @@ -8,9 +8,11 @@ export interface ModalMethods { } export type RegisterFn = (modalMethods: ModalMethods, uuid?: string) => void; + export interface ReturnMethods extends ModalMethods { openModal: (props?: boolean, data?: T, openOnSet?: boolean) => void; } + export type UseModalReturnType = [RegisterFn, ReturnMethods]; export interface ReturnInnerMethods extends ModalMethods { @@ -18,6 +20,7 @@ export interface ReturnInnerMethods extends ModalMethods { changeLoading: (loading: boolean) => void; changeOkLoading: (loading: boolean) => void; } + export type UseModalInnerReturnType = [RegisterFn, ReturnInnerMethods]; export interface ModalProps { diff --git a/src/components/Modal/src/useFullScreen.ts b/src/components/Modal/src/useFullScreen.ts new file mode 100644 index 0000000000000000000000000000000000000000..8680df5c0e0779e147ea8a563fd2fb95834aaad2 --- /dev/null +++ b/src/components/Modal/src/useFullScreen.ts @@ -0,0 +1,44 @@ +import { computed, Ref, ref, unref } from 'vue'; + +export interface UseFullScreenContext { + wrapClassName: Ref; + modalWrapperRef: Ref; + extHeightRef: Ref; +} + +export function useFullScreen(context: UseFullScreenContext) { + const formerHeightRef = ref(0); + const fullScreenRef = ref(false); + + const getWrapClassName = computed(() => { + const clsName = unref(context.wrapClassName) || ''; + + return unref(fullScreenRef) ? `fullscreen-modal ${clsName} ` : unref(clsName); + }); + + function handleFullScreen(e: Event) { + e && e.stopPropagation(); + fullScreenRef.value = !unref(fullScreenRef); + + const modalWrapper = unref(context.modalWrapperRef); + + 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(context.extHeightRef)}px`; + } else { + modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`; + } + } + return { getWrapClassName, handleFullScreen, fullScreenRef }; +} diff --git a/src/components/Modal/src/useModal.ts b/src/components/Modal/src/useModal.ts index 4203bbb8b0889dbccb93f2b5db3dd6606c3f51cb..c1e7a6340413baea288bc5550e5cf2150d095d99 100644 --- a/src/components/Modal/src/useModal.ts +++ b/src/components/Modal/src/useModal.ts @@ -5,9 +5,21 @@ import type { ReturnMethods, UseModalInnerReturnType, } from './types'; -import { ref, onUnmounted, unref, getCurrentInstance, reactive, watchEffect, nextTick } from 'vue'; + +import { + ref, + onUnmounted, + unref, + getCurrentInstance, + reactive, + watchEffect, + nextTick, + toRaw, +} from 'vue'; import { isProdMode } from '/@/utils/env'; import { isFunction } from '/@/utils/is'; +import { isEqual } from 'lodash-es'; +import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; const dataTransferRef = reactive({}); /** @@ -20,6 +32,7 @@ export function useModal(): UseModalReturnType { const modalRef = ref>(null); const loadedRef = ref>(false); const uidRef = ref(''); + function register(modalMethod: ModalMethods, uuid: string) { uidRef.value = uuid; @@ -52,13 +65,16 @@ export function useModal(): UseModalReturnType { visible: visible, }); - if (data) { - dataTransferRef[unref(uidRef)] = openOnSet - ? { - ...data, - __t__: Date.now(), - } - : data; + if (!data) return; + + if (openOnSet) { + dataTransferRef[unref(uidRef)] = null; + dataTransferRef[unref(uidRef)] = data; + return; + } + const equal = isEqual(toRaw(dataTransferRef[unref(uidRef)]), data); + if (!equal) { + dataTransferRef[unref(uidRef)] = data; } }, }; @@ -66,7 +82,7 @@ export function useModal(): UseModalReturnType { } export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => { - const modalInstanceRef = ref(null); + const modalInstanceRef = ref>(null); const currentInstall = getCurrentInstance(); const uidRef = ref(''); @@ -83,6 +99,11 @@ export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => { }; const register = (modalInstance: ModalMethods, uuid: string) => { + isProdMode() && + tryOnUnmounted(() => { + modalInstanceRef.value = null; + }); + uidRef.value = uuid; modalInstanceRef.value = modalInstance; currentInstall.emit('register', modalInstance); diff --git a/src/components/Modal/src/useModalContext.ts b/src/components/Modal/src/useModalContext.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d8c2fb8915c71e67b4fedb591e94ee5a5cdba6a --- /dev/null +++ b/src/components/Modal/src/useModalContext.ts @@ -0,0 +1,16 @@ +import { InjectionKey } from 'vue'; +import { createContext, useContext } from '/@/hooks/core/useContext'; + +export interface ModalContextProps { + redoModalHeight: () => void; +} + +const modalContextInjectKey: InjectionKey = Symbol(); + +export function createModalContext(context: ModalContextProps) { + return createContext(context, modalContextInjectKey); +} + +export function useModalContext() { + return useContext(modalContextInjectKey); +} diff --git a/src/components/Modal/src/useModalDrag.ts b/src/components/Modal/src/useModalDrag.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff05b7b13a66162210cf17dcfb5228cd2d42a1ab --- /dev/null +++ b/src/components/Modal/src/useModalDrag.ts @@ -0,0 +1,107 @@ +import { Ref, unref, watchEffect } from 'vue'; +import { useTimeoutFn } from '/@/hooks/core/useTimeout'; + +export interface UseModalDragMoveContext { + draggable: Ref; + destroyOnClose: Ref | undefined; + visible: Ref; +} + +export function useModalDragMove(context: UseModalDragMoveContext) { + const getStyle = (dom: any, attr: any) => { + return getComputedStyle(dom)[attr]; + }; + const drag = (wrap: any) => { + if (!wrap) return; + wrap.setAttribute('data-drag', unref(context.draggable)); + const dialogHeaderEl = wrap.querySelector('.ant-modal-header'); + const dragDom = wrap.querySelector('.ant-modal'); + + if (!dialogHeaderEl || !dragDom || !unref(context.draggable)) return; + + dialogHeaderEl.style.cursor = 'move'; + + dialogHeaderEl.onmousedown = (e: any) => { + if (!e) return; + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = e.clientX; + const disY = e.clientY; + const screenWidth = document.body.clientWidth; // body当前宽度 + const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) + + const dragDomWidth = dragDom.offsetWidth; // 对话框宽度 + const dragDomheight = dragDom.offsetHeight; // 对话框高度 + + const minDragDomLeft = dragDom.offsetLeft; + + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; + const minDragDomTop = dragDom.offsetTop; + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; + // 获取到的值带px 正则匹配替换 + const domLeft = getStyle(dragDom, 'left'); + const domTop = getStyle(dragDom, 'top'); + let styL = +domLeft; + let styT = +domTop; + + // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px + if (domLeft.includes('%')) { + styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100); + styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100); + } else { + styL = +domLeft.replace(/px/g, ''); + styT = +domTop.replace(/px/g, ''); + } + + document.onmousemove = function (e) { + // 通过事件委托,计算移动的距离 + let left = e.clientX - disX; + let top = e.clientY - disY; + + // 边界处理 + if (-left > minDragDomLeft) { + left = -minDragDomLeft; + } else if (left > maxDragDomLeft) { + left = maxDragDomLeft; + } + + if (-top > minDragDomTop) { + top = -minDragDomTop; + } else if (top > maxDragDomTop) { + top = maxDragDomTop; + } + + // 移动当前元素 + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; + }; + + document.onmouseup = () => { + document.onmousemove = null; + document.onmouseup = null; + }; + }; + }; + + const handleDrag = () => { + const dragWraps = document.querySelectorAll('.ant-modal-wrap'); + for (const wrap of Array.from(dragWraps)) { + if (!wrap) continue; + const display = getStyle(wrap, 'display'); + const draggable = wrap.getAttribute('data-drag'); + if (display !== 'none') { + // 拖拽位置 + if (draggable === null || unref(context.destroyOnClose)) { + drag(wrap); + } + } + } + }; + + watchEffect(() => { + if (!unref(context.visible) || !unref(context.draggable)) { + return; + } + useTimeoutFn(() => { + handleDrag(); + }, 30); + }); +} diff --git a/src/components/Scrollbar/src/Scrollbar.tsx b/src/components/Scrollbar/src/Scrollbar.tsx index 54c4a4a7f1296cb08d0f86bf1dd7aec8fd139beb..4a82c1adc5f34ede787b6bbdd1f72cfef094b21d 100644 --- a/src/components/Scrollbar/src/Scrollbar.tsx +++ b/src/components/Scrollbar/src/Scrollbar.tsx @@ -65,7 +65,7 @@ export default defineComponent({ } onMounted(() => { - tryTsxEmit((instance) => { + tryTsxEmit((instance) => { instance.wrap = unref(wrapElRef); }); diff --git a/src/components/Table/src/hooks/useTableScroll.ts b/src/components/Table/src/hooks/useTableScroll.ts index ac61e18f3e5c46c13815233a5cf8756f6b0629c6..88962fa62cc2956863797496a7dca4772510ee76 100644 --- a/src/components/Table/src/hooks/useTableScroll.ts +++ b/src/components/Table/src/hooks/useTableScroll.ts @@ -1,20 +1,19 @@ import type { BasicTableProps } from '../types/table'; import { computed, Ref, onMounted, unref, ref, nextTick, ComputedRef, watch } from 'vue'; -import { injectModal } from '/@/components/Modal/src/provideModal'; - import { getViewportOffset } from '/@/utils/domUtils'; import { isBoolean } from '/@/utils/is'; import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; import { useProps } from './useProps'; +import { useModalContext } from '/@/components/Modal'; export function useTableScroll(refProps: ComputedRef, tableElRef: Ref) { const { propsRef } = useProps(refProps); const tableHeightRef: Ref = ref(null); - const redoModalHeight = injectModal(); + const modalFn = useModalContext(); watch( () => unref(propsRef).canResize, @@ -93,7 +92,7 @@ export function useTableScroll(refProps: ComputedRef, tableElRe tableHeightRef.value = tableHeightRef.value! > maxHeight! ? (maxHeight as number) : tableHeightRef.value; // 解决表格放modal内的时候,modal自适应高度计算问题 - redoModalHeight && redoModalHeight(); + modalFn?.redoModalHeight?.(); }, 16); } diff --git a/src/components/Tree/src/BasicTree.tsx b/src/components/Tree/src/BasicTree.tsx index 68f298514f486bb2ea549a079e54755969b141df..f49cfb61bb54aaaa37330a1c0c4c94409be189ee 100644 --- a/src/components/Tree/src/BasicTree.tsx +++ b/src/components/Tree/src/BasicTree.tsx @@ -1,6 +1,6 @@ import './index.less'; -import type { ReplaceFields, TreeItem, Keys, CheckKeys } from './types'; +import type { ReplaceFields, TreeItem, Keys, CheckKeys, TreeActionType } from './types'; import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue'; import { Tree } from 'ant-design-vue'; @@ -124,7 +124,6 @@ export default defineComponent({ title: () => ( - {' '} {titleField && anyItem[titleField]} {renderAction(item)} @@ -183,7 +182,7 @@ export default defineComponent({ state.checkedKeys = props.checkedKeys; }); - tryTsxEmit((currentInstance) => { + tryTsxEmit((currentInstance) => { currentInstance.setExpandedKeys = setExpandedKeys; currentInstance.getExpandedKeys = getExpandedKeys; currentInstance.setSelectedKeys = setSelectedKeys; diff --git a/src/components/Tree/src/useTree.ts b/src/components/Tree/src/useTree.ts index a7b984122c8cd62b32c75b4cafdf62b1dbb9bb6a..6245d9fc7e90dc9de3b0d0bf8140b2b48b68fe5f 100644 --- a/src/components/Tree/src/useTree.ts +++ b/src/components/Tree/src/useTree.ts @@ -10,7 +10,7 @@ export function useTree( getReplaceFields: ComputedRef ) { // 更新节点 - function updateNodeByKey(key: string, node: TreeItem, list: TreeItem[]) { + function updateNodeByKey(key: string, node: TreeItem, list?: TreeItem[]) { if (!key) return; const treeData = list || unref(treeDataRef); const { key: keyField, children: childrenField } = unref(getReplaceFields); @@ -75,7 +75,7 @@ export function useTree( } // 删除节点 - function deleteNodeByKey(key: string, list: TreeItem[]) { + function deleteNodeByKey(key: string, list?: TreeItem[]) { if (!key) return; const treeData = list || unref(treeDataRef); const { key: keyField, children: childrenField } = unref(getReplaceFields); diff --git a/src/components/Verify/src/DragVerify.tsx b/src/components/Verify/src/DragVerify.tsx index 6aa65aee17f450bbbaaede0016708ff37b6c4613..2807165fc31e46d2c6b676473e59d8e06e8b711e 100644 --- a/src/components/Verify/src/DragVerify.tsx +++ b/src/components/Verify/src/DragVerify.tsx @@ -6,6 +6,7 @@ import { getSlot } from '/@/utils/helper/tsxHelper'; import './DragVerify.less'; import { CheckOutlined, DoubleRightOutlined } from '@ant-design/icons-vue'; import { tryTsxEmit } from '/@/utils/helper/vueHelper'; +import type { DragVerifyActionType } from './types'; export default defineComponent({ name: 'BaseDargVerify', props: basicProps, @@ -210,7 +211,7 @@ export default defineComponent({ contentEl.style.width = unref(getContentStyleRef).width; } - tryTsxEmit((instance) => { + tryTsxEmit((instance) => { instance.resume = resume; }); diff --git a/src/hooks/setting/useRootSetting.ts b/src/hooks/setting/useRootSetting.ts index a81a62d7f3db12fdef6b7ca906ebc027394f48e6..7d6a4161471c225040860400cd3e6ac4fa17be75 100644 --- a/src/hooks/setting/useRootSetting.ts +++ b/src/hooks/setting/useRootSetting.ts @@ -46,7 +46,7 @@ export function useRootSetting() { unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED ); - function setRootSetting(setting: RootSetting) { + function setRootSetting(setting: Partial) { appStore.commitProjectConfigState(setting); } diff --git a/src/utils/helper/vueHelper.ts b/src/utils/helper/vueHelper.ts index 347f548da167cc9d9d75b3a921fa3a1d712d4470..cd04bea138df20f5e7eb6fa701ba25891d66a426 100644 --- a/src/utils/helper/vueHelper.ts +++ b/src/utils/helper/vueHelper.ts @@ -7,6 +7,7 @@ import { onUnmounted, nextTick, reactive, + ComponentInternalInstance, } from 'vue'; export function explicitComputed(source: WatchSource, fn: () => T) { @@ -29,8 +30,10 @@ export function tryOnUnmounted(fn: () => Promise | void) { getCurrentInstance() && onUnmounted(fn); } -export function tryTsxEmit(fn: (_instance: any) => Promise | void) { - const instance = getCurrentInstance(); +export function tryTsxEmit( + fn: (_instance: T) => Promise | void +) { + const instance = getCurrentInstance() as any; instance && fn.call(null, instance); }