|
@@ -4,85 +4,103 @@ import {ElDialog, ElIcon, useEscapeKeydown} from "element-plus";
|
|
|
import {useVModels} from "@vueuse/core";
|
|
|
// @ts-ignore
|
|
|
import {Close} from '@element-plus/icons-vue'
|
|
|
-import {computed, withDefaults} from "vue";
|
|
|
+import {computed, PropType} from "vue";
|
|
|
import sleep from "@/utils/sleep";
|
|
|
|
|
|
-const props = withDefaults(
|
|
|
- defineProps<{
|
|
|
- modelValue?: boolean,
|
|
|
- title?: string,
|
|
|
- width?: string | number,
|
|
|
- titleAlign?: 'center' | 'left',
|
|
|
- titleIcon?: any | null,
|
|
|
- titleIconColor?: string,
|
|
|
- closeOnClickModal?: boolean,
|
|
|
- bodyCenter?: boolean
|
|
|
- }>(),
|
|
|
- {
|
|
|
- title: '弹窗',
|
|
|
- width: '420px',
|
|
|
- titleAlign: 'center',
|
|
|
- titleIcon: null,
|
|
|
- titleIconColor: '',
|
|
|
- closeOnClickModal: true,
|
|
|
- bodyCenter: false
|
|
|
- }
|
|
|
-)
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ modelValue: {
|
|
|
+ type: Boolean,
|
|
|
+ },
|
|
|
+ title: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ width: {
|
|
|
+ type: [String, Number],
|
|
|
+ default: '30%'
|
|
|
+ },
|
|
|
+ titleAlign: {
|
|
|
+ type: String as PropType<'center' | 'left'>,
|
|
|
+ default: 'center'
|
|
|
+ },
|
|
|
+ titleIcon: {
|
|
|
+ type: [String, Object],
|
|
|
+ default: null
|
|
|
+ },
|
|
|
+ titleIconColor: {
|
|
|
+ type: String,
|
|
|
+ default: '#409EFF'
|
|
|
+ },
|
|
|
+ closeOnClickModal: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ closeOnPressEscape: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ beforeClose: {
|
|
|
+ type: Function as PropType<(done: () => void, closeMode: string) => void>,
|
|
|
+ },
|
|
|
+ top: {
|
|
|
+ type: String,
|
|
|
+ },
|
|
|
+})
|
|
|
|
|
|
const emit = defineEmits(['update:modelValue'])
|
|
|
const {modelValue, titleIcon} = useVModels(props, emit)
|
|
|
const dialogRef = useCompRef(ElDialog)
|
|
|
|
|
|
-let elOverlay: HTMLDivElement = null
|
|
|
-
|
|
|
async function handleMakeClick() {
|
|
|
- if (!props.closeOnClickModal) {
|
|
|
- const dialog = (dialogRef.value.dialogContentRef.$el as HTMLDivElement).parentElement
|
|
|
- dialog.style.transition = 'transform .2s ease-out'
|
|
|
- dialog.style.transform = 'scale(1.08)'
|
|
|
- await sleep(200)
|
|
|
- dialog.style.transform = ''
|
|
|
- await sleep(200)
|
|
|
- dialog.style.transition = ''
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function handleOpened() {
|
|
|
- elOverlay = (dialogRef.value.dialogContentRef.$el as HTMLDivElement).parentElement.parentElement as HTMLDivElement
|
|
|
- elOverlay.addEventListener('click', handleMakeClick);
|
|
|
+ const dialog = (dialogRef.value.dialogContentRef.$el as HTMLDivElement)
|
|
|
+ const oldTransform = dialog.style.transform!.replace("scale(1.08)", "")
|
|
|
+
|
|
|
+ dialog.style.transition = 'transform .2s ease-out'
|
|
|
+ dialog.style.transform = `${oldTransform} scale(1.08)`
|
|
|
+ await sleep(200)
|
|
|
+ dialog.style.transform = `${oldTransform}`
|
|
|
+ dialog.style.transition = ''
|
|
|
}
|
|
|
|
|
|
-function handleClosed() {
|
|
|
- if (elOverlay) {
|
|
|
- elOverlay!.removeEventListener('click', handleMakeClick)
|
|
|
+function beforeClose(done, val) {
|
|
|
+ if (!props.closeOnClickModal && (val === 'modal' || val === 'icon')) {
|
|
|
+ handleMakeClick()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!props.closeOnPressEscape && val === 'esc') {
|
|
|
+ handleMakeClick()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (props.beforeClose) {
|
|
|
+ props.beforeClose(done, val)
|
|
|
+ } else {
|
|
|
+ done()
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-function beforeClose(done, val) {
|
|
|
- console.log(val)
|
|
|
- done()
|
|
|
}
|
|
|
|
|
|
const dialogStyle = computed(() => {
|
|
|
return {
|
|
|
'--header-align': props.titleAlign,
|
|
|
'--title-icon-color': props.titleIconColor,
|
|
|
- '--body-center': props.bodyCenter ? 'auto' : '15vh auto 50px auto'
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+defineExpose({
|
|
|
+ handleMakeClick
|
|
|
+})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<el-dialog v-model="modelValue"
|
|
|
:title="props.title"
|
|
|
+ dialog-animation="enlarge"
|
|
|
:before-close="beforeClose"
|
|
|
class="cy-root"
|
|
|
:style="dialogStyle"
|
|
|
- @opened="handleOpened"
|
|
|
- @closed="handleClosed"
|
|
|
- :close-on-click-modal="props.closeOnClickModal"
|
|
|
+ :top="props.top"
|
|
|
ref="dialogRef"
|
|
|
:show-close="false"
|
|
|
modal-class="cy_dialog-modal"
|
|
@@ -112,59 +130,60 @@ const dialogStyle = computed(() => {
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
|
+.enlarge-enter-active {
|
|
|
+ animation: anim-open .2s ease;
|
|
|
+}
|
|
|
|
|
|
-.cy_dialog-modal {
|
|
|
- --el-overlay-color-lighter: rgba(0, 0, 0, .2);
|
|
|
+.enlarge-leave-active {
|
|
|
+ animation: anim-close .2s ease;
|
|
|
+}
|
|
|
|
|
|
- &.dialog-fade-enter-active {
|
|
|
- animation: anim-open .2s ease;
|
|
|
+@keyframes anim-close {
|
|
|
+ 0% {
|
|
|
+ transform: scale(1);
|
|
|
+ background-color: transparent;
|
|
|
}
|
|
|
|
|
|
- &.dialog-fade-leave-active {
|
|
|
- animation: anim-close .2s ease;
|
|
|
+ 100% {
|
|
|
+ transform: scale(0);
|
|
|
+ background-color: transparent;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- @keyframes anim-close {
|
|
|
- 0% {
|
|
|
- transform: scale(1);
|
|
|
- background-color: transparent;
|
|
|
- }
|
|
|
-
|
|
|
- 100% {
|
|
|
- transform: scale(0);
|
|
|
- background-color: transparent;
|
|
|
- }
|
|
|
+@keyframes anim-open {
|
|
|
+ 0% {
|
|
|
+ opacity: 0;
|
|
|
+ transform: scale(.8);
|
|
|
+ background-color: transparent;
|
|
|
}
|
|
|
-
|
|
|
- @keyframes anim-open {
|
|
|
- 0% {
|
|
|
- opacity: 0;
|
|
|
- transform: scale(.8);
|
|
|
- background-color: transparent;
|
|
|
- }
|
|
|
- 40% {
|
|
|
- transform: scale(1.08);
|
|
|
- background-color: transparent;
|
|
|
- }
|
|
|
- 80% {
|
|
|
- transform: scale(0.98);
|
|
|
- background-color: transparent;
|
|
|
- }
|
|
|
- 100% {
|
|
|
- opacity: 1;
|
|
|
- transform: scale(1);
|
|
|
- background-color: transparent;
|
|
|
- }
|
|
|
+ 40% {
|
|
|
+ transform: scale(1.08);
|
|
|
+ background-color: transparent;
|
|
|
+ }
|
|
|
+ 80% {
|
|
|
+ transform: scale(0.98);
|
|
|
+ background-color: transparent;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ opacity: 1;
|
|
|
+ transform: scale(1);
|
|
|
+ background-color: transparent;
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+.cy_dialog-modal {
|
|
|
+ --el-overlay-color-lighter: rgba(0, 0, 0, .2);
|
|
|
|
|
|
.el-overlay-dialog {
|
|
|
overflow: hidden;
|
|
|
+ //display: flex;
|
|
|
+ //justify-content: center;
|
|
|
+ //align-content: center;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.cy-root {
|
|
|
border-radius: 20px;
|
|
|
- margin: var(--body-center);
|
|
|
|
|
|
header {
|
|
|
border-radius: 20px;
|