forked from wangjiadong/comp
parent
1f487a8267
commit
cc1760bb75
7 changed files with 779 additions and 0 deletions
@ -0,0 +1,6 @@ |
||||
import { withInstall } from '/@/utils'; |
||||
import basicDrawer from './src/BasicDrawer.vue'; |
||||
|
||||
export const BasicDrawerYX = withInstall(basicDrawer); |
||||
export * from './src/typing'; |
||||
export { useDrawerYX, useDrawerInner } from './src/useDrawerYX'; |
@ -0,0 +1,237 @@ |
||||
<template> |
||||
<Drawer :class="prefixCls" @close="onClose" v-bind="getBindValues"> |
||||
<template #title v-if="!$slots.title"> |
||||
<DrawerHeader :title="getMergeProps.title" :isDetail="isDetail" :showDetailBack="showDetailBack" @close="onClose"> |
||||
<template #titleToolbar> |
||||
<slot name="titleToolbar"></slot> |
||||
</template> |
||||
</DrawerHeader> |
||||
</template> |
||||
<template v-else #title> |
||||
<slot name="title"></slot> |
||||
</template> |
||||
|
||||
<ScrollContainer :style="getScrollContentStyle" v-loading="getLoading" :loading-tip="loadingText || t('common.loadingText')"> |
||||
<slot></slot> |
||||
</ScrollContainer> |
||||
<DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk" :height="getFooterHeight"> |
||||
<template #[item]="data" v-for="item in Object.keys($slots)"> |
||||
<slot :name="item" v-bind="data || {}"></slot> |
||||
</template> |
||||
</DrawerFooter> |
||||
</Drawer> |
||||
</template> |
||||
<script lang="ts"> |
||||
import type { DrawerInstance, DrawerProps } from './typing'; |
||||
import type { CSSProperties } from 'vue'; |
||||
import { defineComponent, ref, computed, watch, unref, nextTick, toRaw, getCurrentInstance } from 'vue'; |
||||
import { Drawer } from 'ant-design-vue'; |
||||
import { useI18n } from '/@/hooks/web/useI18n'; |
||||
import { isFunction, isNumber } from '/@/utils/is'; |
||||
import { deepMerge } from '/@/utils'; |
||||
import DrawerFooter from './components/DrawerFooter.vue'; |
||||
import DrawerHeader from './components/DrawerHeader.vue'; |
||||
import { ScrollContainer } from '/@/components/Container'; |
||||
import { basicProps } from './props'; |
||||
import { useDesign } from '/@/hooks/web/useDesign'; |
||||
import { useAttrs } from '/@/hooks/core/useAttrs'; |
||||
|
||||
export default defineComponent({ |
||||
components: { Drawer, ScrollContainer, DrawerFooter, DrawerHeader }, |
||||
inheritAttrs: false, |
||||
props: basicProps, |
||||
emits: ['visible-change', 'ok', 'close', 'register'], |
||||
setup(props, { emit }) { |
||||
const visibleRef = ref(false); |
||||
const attrs = useAttrs(); |
||||
const propsRef = ref<Partial<Nullable<DrawerProps>>>(null); |
||||
|
||||
const { t } = useI18n(); |
||||
const { prefixVar, prefixCls } = useDesign('basic-drawer'); |
||||
|
||||
const drawerInstance: DrawerInstance = { |
||||
setDrawerProps: setDrawerProps, |
||||
emitVisible: undefined, |
||||
}; |
||||
|
||||
const instance = getCurrentInstance(); |
||||
|
||||
instance && emit('register', drawerInstance, instance.uid); |
||||
|
||||
const getMergeProps = computed((): DrawerProps => { |
||||
return deepMerge(toRaw(props), unref(propsRef)); |
||||
}); |
||||
|
||||
const getProps = computed((): DrawerProps => { |
||||
const opt = { |
||||
placement: 'right', |
||||
...unref(attrs), |
||||
...unref(getMergeProps), |
||||
visible: unref(visibleRef), |
||||
}; |
||||
opt.title = undefined; |
||||
let { isDetail, width, wrapClassName, getContainer } = opt; |
||||
if (isDetail) { |
||||
if (!width) { |
||||
opt.width = '100%'; |
||||
} |
||||
const detailCls = `${prefixCls}__detail`; |
||||
wrapClassName = opt['class'] ? opt['class'] : wrapClassName; |
||||
opt.class = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls; |
||||
|
||||
if (!getContainer) { |
||||
// TODO type error? |
||||
opt.getContainer = `.${prefixVar}-layout-content` as any; |
||||
} |
||||
} |
||||
return opt as DrawerProps; |
||||
}); |
||||
|
||||
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})`, |
||||
}; |
||||
}); |
||||
|
||||
const getLoading = computed(() => { |
||||
return !!unref(getProps)?.loading; |
||||
}); |
||||
|
||||
watch( |
||||
() => props.visible, |
||||
(newVal, oldVal) => { |
||||
if (newVal !== oldVal) visibleRef.value = newVal; |
||||
}, |
||||
{ deep: true } |
||||
); |
||||
|
||||
watch( |
||||
() => visibleRef.value, |
||||
(visible) => { |
||||
nextTick(() => { |
||||
emit('visible-change', visible); |
||||
instance && drawerInstance.emitVisible?.(visible, instance.uid); |
||||
}); |
||||
} |
||||
); |
||||
|
||||
// Cancel event |
||||
async function onClose(e: Recordable) { |
||||
const { closeFunc } = unref(getProps); |
||||
emit('close', e); |
||||
if (closeFunc && isFunction(closeFunc)) { |
||||
const res = await closeFunc(); |
||||
visibleRef.value = !res; |
||||
return; |
||||
} |
||||
visibleRef.value = false; |
||||
} |
||||
|
||||
function setDrawerProps(props: Partial<DrawerProps>): void { |
||||
// Keep the last setDrawerProps |
||||
propsRef.value = deepMerge(unref(propsRef) || ({} as any), props); |
||||
|
||||
if (Reflect.has(props, 'visible')) { |
||||
visibleRef.value = !!props.visible; |
||||
} |
||||
} |
||||
|
||||
function handleOk() { |
||||
emit('ok'); |
||||
} |
||||
|
||||
return { |
||||
onClose, |
||||
t, |
||||
prefixCls, |
||||
getMergeProps: getMergeProps as any, |
||||
getScrollContentStyle, |
||||
getProps: getProps as any, |
||||
getLoading, |
||||
getBindValues, |
||||
getFooterHeight, |
||||
handleOk, |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less"> |
||||
@header-height: 60px; |
||||
@detail-header-height: 40px; |
||||
@prefix-cls: ~'@{namespace}-basic-drawer'; |
||||
@prefix-cls-detail: ~'@{namespace}-basic-drawer__detail'; |
||||
|
||||
.@{prefix-cls} { |
||||
.ant-drawer-wrapper-body { |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.ant-drawer-close { |
||||
&:hover { |
||||
color: @error-color; |
||||
} |
||||
} |
||||
|
||||
.ant-drawer-body { |
||||
height: calc(100% - @header-height); |
||||
padding: 0; |
||||
background-color: @component-background; |
||||
|
||||
.scrollbar__wrap { |
||||
padding: 16px !important; |
||||
margin-bottom: 0 !important; |
||||
} |
||||
|
||||
> .scrollbar > .scrollbar__bar.is-horizontal { |
||||
display: none; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.@{prefix-cls-detail} { |
||||
position: absolute; |
||||
|
||||
.ant-drawer-header { |
||||
width: 100%; |
||||
height: @detail-header-height; |
||||
padding: 0; |
||||
border-top: 1px solid @border-color-base; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.ant-drawer-title { |
||||
height: 100%; |
||||
} |
||||
|
||||
.ant-drawer-close { |
||||
height: @detail-header-height; |
||||
line-height: @detail-header-height; |
||||
} |
||||
|
||||
.scrollbar__wrap { |
||||
padding: 0 !important; |
||||
} |
||||
|
||||
.ant-drawer-body { |
||||
height: calc(100% - @detail-header-height); |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,75 @@ |
||||
<template> |
||||
<div :class="prefixCls" :style="getStyle" v-if="showFooter || $slots.footer"> |
||||
<template v-if="!$slots.footer"> |
||||
<slot name="insertFooter"></slot> |
||||
<a-button v-bind="cancelButtonProps" @click="handleClose" class="mr-2" v-if="showCancelBtn"> |
||||
{{ cancelText }} |
||||
</a-button> |
||||
<slot name="centerFooter"></slot> |
||||
<a-button :type="okType" @click="handleOk" v-bind="okButtonProps" class="mr-2" :loading="confirmLoading" v-if="showOkBtn"> |
||||
{{ okText }} |
||||
</a-button> |
||||
<slot name="appendFooter"></slot> |
||||
</template> |
||||
|
||||
<template v-else> |
||||
<slot name="footer"></slot> |
||||
</template> |
||||
</div> |
||||
</template> |
||||
<script lang="ts"> |
||||
import type { CSSProperties } from 'vue'; |
||||
import { defineComponent, computed } from 'vue'; |
||||
import { useDesign } from '/@/hooks/web/useDesign'; |
||||
|
||||
import { footerProps } from '../props'; |
||||
export default defineComponent({ |
||||
name: 'BasicDrawerFooter', |
||||
props: { |
||||
...footerProps, |
||||
height: { |
||||
type: String, |
||||
default: '60px', |
||||
}, |
||||
}, |
||||
emits: ['ok', 'close'], |
||||
setup(props, { emit }) { |
||||
const { prefixCls } = useDesign('basic-drawer-footer'); |
||||
|
||||
const getStyle = computed((): CSSProperties => { |
||||
const heightStr = `${props.height}`; |
||||
return { |
||||
height: heightStr, |
||||
lineHeight: heightStr, |
||||
}; |
||||
}); |
||||
|
||||
function handleOk() { |
||||
emit('ok'); |
||||
} |
||||
|
||||
function handleClose() { |
||||
emit('close'); |
||||
} |
||||
return { handleOk, prefixCls, handleClose, getStyle }; |
||||
}, |
||||
}); |
||||
</script> |
||||
|
||||
<style lang="less"> |
||||
@prefix-cls: ~'@{namespace}-basic-drawer-footer'; |
||||
@footer-height: 60px; |
||||
.@{prefix-cls} { |
||||
position: absolute; |
||||
bottom: 0; |
||||
width: 100%; |
||||
padding: 0 12px 0 20px; |
||||
text-align: right; |
||||
background-color: @component-background; |
||||
border-top: 1px solid @border-color-base; |
||||
|
||||
> * { |
||||
margin-right: 8px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,74 @@ |
||||
<template> |
||||
<BasicTitle v-if="!isDetail" :class="prefixCls"> |
||||
<slot name="title"></slot> |
||||
{{ !$slots.title ? title : '' }} |
||||
</BasicTitle> |
||||
|
||||
<div :class="[prefixCls, `${prefixCls}--detail`]" v-else> |
||||
<span :class="`${prefixCls}__twrap`"> |
||||
<span @click="handleClose" v-if="showDetailBack"> |
||||
<ArrowLeftOutlined :class="`${prefixCls}__back`" /> |
||||
</span> |
||||
<span v-if="title">{{ title }}</span> |
||||
</span> |
||||
|
||||
<span :class="`${prefixCls}__toolbar`"> |
||||
<slot name="titleToolbar"></slot> |
||||
</span> |
||||
</div> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { defineComponent } from 'vue'; |
||||
import { BasicTitle } from '/@/components/Basic'; |
||||
import { ArrowLeftOutlined } from '@ant-design/icons-vue'; |
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign'; |
||||
|
||||
import { propTypes } from '/@/utils/propTypes'; |
||||
export default defineComponent({ |
||||
name: 'BasicDrawerHeader', |
||||
components: { BasicTitle, ArrowLeftOutlined }, |
||||
props: { |
||||
isDetail: propTypes.bool, |
||||
showDetailBack: propTypes.bool, |
||||
title: propTypes.string, |
||||
}, |
||||
emits: ['close'], |
||||
setup(_, { emit }) { |
||||
const { prefixCls } = useDesign('basic-drawer-header'); |
||||
|
||||
function handleClose() { |
||||
emit('close'); |
||||
} |
||||
|
||||
return { prefixCls, handleClose }; |
||||
}, |
||||
}); |
||||
</script> |
||||
|
||||
<style lang="less"> |
||||
@prefix-cls: ~'@{namespace}-basic-drawer-header'; |
||||
@footer-height: 60px; |
||||
.@{prefix-cls} { |
||||
display: flex; |
||||
height: 100%; |
||||
align-items: center; |
||||
|
||||
&__back { |
||||
padding: 0 12px; |
||||
cursor: pointer; |
||||
|
||||
&:hover { |
||||
color: @primary-color; |
||||
} |
||||
} |
||||
|
||||
&__twrap { |
||||
flex: 1; |
||||
} |
||||
|
||||
&__toolbar { |
||||
padding-right: 50px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,45 @@ |
||||
import type { PropType } from 'vue'; |
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n'; |
||||
const { t } = useI18n(); |
||||
|
||||
export const footerProps = { |
||||
confirmLoading: { type: Boolean }, |
||||
/** |
||||
* @description: Show close button |
||||
*/ |
||||
showCancelBtn: { type: Boolean, default: true }, |
||||
cancelButtonProps: Object as PropType<Recordable>, |
||||
cancelText: { type: String, default: t('common.cancelText') }, |
||||
/** |
||||
* @description: Show confirmation button |
||||
*/ |
||||
showOkBtn: { type: Boolean, default: true }, |
||||
okButtonProps: Object as PropType<Recordable>, |
||||
okText: { type: String, default: t('common.okText') }, |
||||
okType: { type: String, default: 'primary' }, |
||||
showFooter: { type: Boolean }, |
||||
footerHeight: { |
||||
type: [String, Number] as PropType<string | number>, |
||||
default: 60, |
||||
}, |
||||
}; |
||||
export const basicProps = { |
||||
class: {type: [String, Object, Array]}, |
||||
isDetail: { type: Boolean }, |
||||
title: { type: String, default: '' }, |
||||
loadingText: { type: String }, |
||||
showDetailBack: { type: Boolean, default: true }, |
||||
visible: { type: Boolean }, |
||||
loading: { type: Boolean }, |
||||
maskClosable: { type: Boolean, default: true }, |
||||
getContainer: { |
||||
type: [Object, String] as PropType<any>, |
||||
}, |
||||
closeFunc: { |
||||
type: [Function, Object] as PropType<any>, |
||||
default: null, |
||||
}, |
||||
destroyOnClose: { type: Boolean }, |
||||
...footerProps, |
||||
}; |
@ -0,0 +1,196 @@ |
||||
import type { ButtonProps } from 'ant-design-vue/lib/button/buttonTypes'; |
||||
import type { CSSProperties, VNodeChild, ComputedRef } from 'vue'; |
||||
import type { ScrollContainerOptions } from '/@/components/Container/index'; |
||||
|
||||
export interface DrawerInstance { |
||||
setDrawerProps: (props: Partial<DrawerProps> | boolean) => void; |
||||
emitVisible?: (visible: boolean, uid: number) => void; |
||||
} |
||||
|
||||
export interface ReturnMethods extends DrawerInstance { |
||||
openDrawerYX: <T = any>(visible?: boolean, data?: T, openOnSet?: boolean) => void; |
||||
closeDrawer: () => void; |
||||
getVisible?: ComputedRef<boolean>; |
||||
} |
||||
|
||||
export type RegisterFn = (drawerInstance: DrawerInstance, uuid?: string) => void; |
||||
|
||||
export interface ReturnInnerMethods extends DrawerInstance { |
||||
closeDrawer: () => void; |
||||
changeLoading: (loading: boolean) => void; |
||||
changeOkLoading: (loading: boolean) => void; |
||||
getVisible?: ComputedRef<boolean>; |
||||
} |
||||
|
||||
export type UseDrawerReturnType = [RegisterFn, ReturnMethods]; |
||||
|
||||
export type UseDrawerInnerReturnType = [RegisterFn, ReturnInnerMethods]; |
||||
|
||||
export interface DrawerFooterProps { |
||||
showOkBtn: boolean; |
||||
showCancelBtn: boolean; |
||||
/** |
||||
* Text of the Cancel button |
||||
* @default 'cancel' |
||||
* @type string |
||||
*/ |
||||
cancelText: string; |
||||
/** |
||||
* Text of the OK button |
||||
* @default 'OK' |
||||
* @type string |
||||
*/ |
||||
okText: string; |
||||
|
||||
/** |
||||
* Button type of the OK button |
||||
* @default 'primary' |
||||
* @type string |
||||
*/ |
||||
okType: 'primary' | 'danger' | 'dashed' | 'ghost' | 'default'; |
||||
/** |
||||
* The ok button props, follow jsx rules |
||||
* @type object |
||||
*/ |
||||
okButtonProps: { props: ButtonProps; on: {} }; |
||||
|
||||
/** |
||||
* The cancel button props, follow jsx rules |
||||
* @type object |
||||
*/ |
||||
cancelButtonProps: { props: ButtonProps; on: {} }; |
||||
/** |
||||
* Whether to apply loading visual effect for OK button or not |
||||
* @default false |
||||
* @type boolean |
||||
*/ |
||||
confirmLoading: boolean; |
||||
|
||||
showFooter: boolean; |
||||
footerHeight: string | number; |
||||
} |
||||
export interface DrawerProps extends DrawerFooterProps { |
||||
isDetail?: boolean; |
||||
loading?: boolean; |
||||
showDetailBack?: boolean; |
||||
visible?: boolean; |
||||
/** |
||||
* Built-in ScrollContainer component configuration |
||||
* @type ScrollContainerOptions |
||||
*/ |
||||
scrollOptions?: ScrollContainerOptions; |
||||
closeFunc?: () => Promise<any>; |
||||
triggerWindowResize?: boolean; |
||||
/** |
||||
* Whether a close (x) button is visible on top right of the Drawer dialog or not. |
||||
* @default true |
||||
* @type boolean |
||||
*/ |
||||
closable?: boolean; |
||||
|
||||
/** |
||||
* Whether to unmount child components on closing drawer or not. |
||||
* @default false |
||||
* @type boolean |
||||
*/ |
||||
destroyOnClose?: boolean; |
||||
|
||||
/** |
||||
* Return the mounted node for Drawer. |
||||
* @default 'body' |
||||
* @type any ( HTMLElement| () => HTMLElement | string) |
||||
*/ |
||||
getContainer?: () => HTMLElement | string; |
||||
|
||||
/** |
||||
* Whether to show mask or not. |
||||
* @default true |
||||
* @type boolean |
||||
*/ |
||||
mask?: boolean; |
||||
|
||||
/** |
||||
* Clicking on the mask (area outside the Drawer) to close the Drawer or not. |
||||
* @default true |
||||
* @type boolean |
||||
*/ |
||||
maskClosable?: boolean; |
||||
|
||||
/** |
||||
* Style for Drawer's mask element. |
||||
* @default {} |
||||
* @type object |
||||
*/ |
||||
maskStyle?: CSSProperties; |
||||
|
||||
/** |
||||
* The title for Drawer. |
||||
* @type any (string | slot) |
||||
*/ |
||||
title?: VNodeChild | JSX.Element; |
||||
|
||||
/** |
||||
* The class name of the container of the Drawer dialog. |
||||
* @type string |
||||
*/ |
||||
class?: string; |
||||
// 兼容老版本的写法(后续可能会删除,优先写class)
|
||||
wrapClassName?: string; |
||||
|
||||
/** |
||||
* Style of wrapper element which **contains mask** compare to `drawerStyle` |
||||
* @type object |
||||
*/ |
||||
wrapStyle?: CSSProperties; |
||||
|
||||
/** |
||||
* Style of the popup layer element |
||||
* @type object |
||||
*/ |
||||
drawerStyle?: CSSProperties; |
||||
|
||||
/** |
||||
* Style of floating layer, typically used for adjusting its position. |
||||
* @type object |
||||
*/ |
||||
bodyStyle?: CSSProperties; |
||||
headerStyle?: CSSProperties; |
||||
|
||||
/** |
||||
* Width of the Drawer dialog. |
||||
* @default 256 |
||||
* @type string | number |
||||
*/ |
||||
width?: string | number; |
||||
|
||||
/** |
||||
* placement is top or bottom, height of the Drawer dialog. |
||||
* @type string | number |
||||
*/ |
||||
height?: string | number; |
||||
|
||||
/** |
||||
* The z-index of the Drawer. |
||||
* @default 1000 |
||||
* @type number |
||||
*/ |
||||
zIndex?: number; |
||||
|
||||
/** |
||||
* The placement of the Drawer. |
||||
* @default 'right' |
||||
* @type string |
||||
*/ |
||||
placement?: 'top' | 'right' | 'bottom' | 'left'; |
||||
afterVisibleChange?: (visible?: boolean) => void; |
||||
keyboard?: boolean; |
||||
/** |
||||
* Specify a callback that will be called when a user clicks mask, close button or Cancel button. |
||||
*/ |
||||
onClose?: (e?: Event) => void; |
||||
} |
||||
export interface DrawerActionType { |
||||
scrollBottom: () => void; |
||||
scrollTo: (to: number) => void; |
||||
getScrollWrap: () => Element | null; |
||||
} |
@ -0,0 +1,146 @@ |
||||
import type { UseDrawerReturnType, DrawerInstance, ReturnMethods, DrawerProps, UseDrawerInnerReturnType } from './typing'; |
||||
import { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw, computed } from 'vue'; |
||||
import { isProdMode } from '/@/utils/env'; |
||||
import { isFunction } from '/@/utils/is'; |
||||
import { tryOnUnmounted } from '@vueuse/core'; |
||||
import { isEqual } from 'lodash-es'; |
||||
import { error } from '/@/utils/log'; |
||||
|
||||
const dataTransferRef = reactive<any>({}); |
||||
|
||||
const visibleData = reactive<{ [key: number]: boolean }>({}); |
||||
|
||||
/** |
||||
* @description: Applicable to separate drawer and call outside |
||||
*/ |
||||
export function useDrawerYX(): UseDrawerReturnType { |
||||
if (!getCurrentInstance()) { |
||||
throw new Error('useDrawer() can only be used inside setup() or functional components!'); |
||||
} |
||||
const drawer = ref<DrawerInstance | null>(null); |
||||
const loaded = ref<Nullable<boolean>>(false); |
||||
const uid = ref<string>(''); |
||||
|
||||
function register(drawerInstance: DrawerInstance, uuid: string) { |
||||
isProdMode() && |
||||
tryOnUnmounted(() => { |
||||
drawer.value = null; |
||||
loaded.value = null; |
||||
dataTransferRef[unref(uid)] = null; |
||||
}); |
||||
|
||||
if (unref(loaded) && isProdMode() && drawerInstance === unref(drawer)) { |
||||
return; |
||||
} |
||||
uid.value = uuid; |
||||
drawer.value = drawerInstance; |
||||
loaded.value = true; |
||||
|
||||
drawerInstance.emitVisible = (visible: boolean, uid: number) => { |
||||
visibleData[uid] = visible; |
||||
}; |
||||
} |
||||
|
||||
const getInstance = () => { |
||||
const instance = unref(drawer); |
||||
if (!instance) { |
||||
error('useDrawer instance is undefined!'); |
||||
} |
||||
return instance; |
||||
}; |
||||
|
||||
const methods: ReturnMethods = { |
||||
setDrawerProps: (props: Partial<DrawerProps>): void => { |
||||
getInstance()?.setDrawerProps(props); |
||||
}, |
||||
|
||||
getVisible: computed((): boolean => { |
||||
return visibleData[~~unref(uid)]; |
||||
}), |
||||
|
||||
openDrawerYX: <T = any>(visible = true, data?: T, openOnSet = true): void => { |
||||
getInstance()?.setDrawerProps({ |
||||
visible: visible, |
||||
}); |
||||
if (!data) return; |
||||
|
||||
if (openOnSet) { |
||||
dataTransferRef[unref(uid)] = null; |
||||
dataTransferRef[unref(uid)] = toRaw(data); |
||||
return; |
||||
} |
||||
const equal = isEqual(toRaw(dataTransferRef[unref(uid)]), toRaw(data)); |
||||
if (!equal) { |
||||
dataTransferRef[unref(uid)] = toRaw(data); |
||||
} |
||||
}, |
||||
closeDrawer: () => { |
||||
getInstance()?.setDrawerProps({ visible: false }); |
||||
}, |
||||
}; |
||||
|
||||
return [register, methods]; |
||||
} |
||||
|
||||
export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => { |
||||
const drawerInstanceRef = ref<Nullable<DrawerInstance>>(null); |
||||
const currentInstance = getCurrentInstance(); |
||||
const uidRef = ref<string>(''); |
||||
|
||||
if (!getCurrentInstance()) { |
||||
throw new Error('useDrawerInner() can only be used inside setup() or functional components!'); |
||||
} |
||||
|
||||
const getInstance = () => { |
||||
const instance = unref(drawerInstanceRef); |
||||
if (!instance) { |
||||
error('useDrawerInner instance is undefined!'); |
||||
return; |
||||
} |
||||
return instance; |
||||
}; |
||||
|
||||
const register = (modalInstance: DrawerInstance, uuid: string) => { |
||||
isProdMode() && |
||||
tryOnUnmounted(() => { |
||||
drawerInstanceRef.value = null; |
||||
}); |
||||
|
||||
uidRef.value = uuid; |
||||
drawerInstanceRef.value = modalInstance; |
||||
currentInstance?.emit('register', modalInstance, uuid); |
||||
}; |
||||
|
||||
watchEffect(() => { |
||||
const data = dataTransferRef[unref(uidRef)]; |
||||
if (!data) return; |
||||
if (!callbackFn || !isFunction(callbackFn)) return; |
||||
nextTick(() => { |
||||
callbackFn(data); |
||||
}); |
||||
}); |
||||
|
||||
return [ |
||||
register, |
||||
{ |
||||
changeLoading: (loading = true) => { |
||||
getInstance()?.setDrawerProps({ loading }); |
||||
}, |
||||
|
||||
changeOkLoading: (loading = true) => { |
||||
getInstance()?.setDrawerProps({ confirmLoading: loading }); |
||||
}, |
||||
getVisible: computed((): boolean => { |
||||
return visibleData[~~unref(uidRef)]; |
||||
}), |
||||
|
||||
closeDrawer: () => { |
||||
getInstance()?.setDrawerProps({ visible: false }); |
||||
}, |
||||
|
||||
setDrawerProps: (props: Partial<DrawerProps>) => { |
||||
getInstance()?.setDrawerProps(props); |
||||
}, |
||||
}, |
||||
]; |
||||
}; |
Loading…
Reference in new issue