|
@@ -0,0 +1,244 @@
|
|
|
+<template>
|
|
|
+ <Transition name="cy-dialog">
|
|
|
+ <div class="cy-dialog__v2"
|
|
|
+ ref="dialogRef"
|
|
|
+ :style="config.fullScreen ? fullScreenStyle : dislogStyle"
|
|
|
+ v-show="config.dialog"
|
|
|
+ :class="config.fullScreen ? 'cy-dialog__fullScreen' : 'cy-dialog__cancelFullScreen' ">
|
|
|
+ <div class="cy-dialog__header" ref="dialogHeadRef"
|
|
|
+ @mousedown.stop.prevent>
|
|
|
+ <div class="cy-dialog__title">
|
|
|
+ <span>
|
|
|
+ {{ config.title }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="cy-dialog__icon">
|
|
|
+ <div style="background-color: rgb(253,201,45)">
|
|
|
+ <i class="iconfont icon-suoxiao"/>
|
|
|
+ </div>
|
|
|
+ <div style="background-color: rgb(40,211,63)">
|
|
|
+ <i class="iconfont"
|
|
|
+ @click="clickFullScreen"
|
|
|
+ :class="config.fullScreen ? 'icon-quxiaoquanping' : 'icon-quanping' ">
|
|
|
+ </i>
|
|
|
+ </div>
|
|
|
+ <div class="cy-dialog__close" style="background-color: rgb(254,98,84)">
|
|
|
+ <i class="iconfont icon-guanbi" @click="closed"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="cy-dialog__main">
|
|
|
+ <slot/>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Transition>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name='XcDialog' lang="ts">
|
|
|
+import {PropType, Ref, ref, watch, onMounted, nextTick} from "vue";
|
|
|
+import {useDraggable, onClickOutside} from '@vueuse/core'
|
|
|
+import {$ref} from "vue/macros";
|
|
|
+
|
|
|
+interface dialogConfig {
|
|
|
+ fullScreen: boolean,
|
|
|
+ title: string,
|
|
|
+ top?: number,
|
|
|
+ dialog: boolean,
|
|
|
+ img?: any,
|
|
|
+ width: '',
|
|
|
+}
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ config: Object as PropType<dialogConfig>
|
|
|
+})
|
|
|
+const emit = defineEmits(['closed'])
|
|
|
+
|
|
|
+
|
|
|
+const dialogRef: Ref<HTMLElement | null> = ref(null)
|
|
|
+const dialogHeadRef: Ref<HTMLElement | null> = ref(null)
|
|
|
+
|
|
|
+onClickOutside(dialogRef, (event) => {
|
|
|
+ closed()
|
|
|
+})
|
|
|
+
|
|
|
+const draggable = ref()
|
|
|
+const fullScreenStyle = $ref({
|
|
|
+ position: 'fixed',
|
|
|
+ top: '0',
|
|
|
+ left: '0',
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ zIndex: 0,
|
|
|
+})
|
|
|
+
|
|
|
+let dislogStyle = $ref({
|
|
|
+ left: '',
|
|
|
+ top: '',
|
|
|
+ zIndex: 0,
|
|
|
+ width: '30%'
|
|
|
+})
|
|
|
+
|
|
|
+const clickFullScreen = () => {
|
|
|
+ let zIndex = [...document.all].reduce((r, e) => Math.max(r, +window.getComputedStyle(e).zIndex || 0), 0)
|
|
|
+ props.config!.fullScreen = !props.config?.fullScreen
|
|
|
+ fullScreenStyle.zIndex = zIndex
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const closed = () => {
|
|
|
+ emit('closed')
|
|
|
+ props.config!.dialog = false
|
|
|
+}
|
|
|
+
|
|
|
+watch(() => props.config?.dialog, () => {
|
|
|
+ if (props.config?.dialog) {
|
|
|
+ let zIndex = [...document.all].reduce((r, e) => Math.max(r, +window.getComputedStyle(e).zIndex || 0), 0)
|
|
|
+ dislogStyle.zIndex = zIndex
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+watch(() => draggable.value?.x, async () => {
|
|
|
+ if (props.config!.fullScreen) return
|
|
|
+ let right = window.innerWidth - dialogRef.value!.clientWidth
|
|
|
+ if (draggable.value.x < 0) {
|
|
|
+ draggable.value.x = 0
|
|
|
+ } else if (draggable.value.x > right) {
|
|
|
+ draggable.value.x = right
|
|
|
+ }
|
|
|
+ dislogStyle.left = draggable.value.x + 'px'
|
|
|
+})
|
|
|
+
|
|
|
+watch(() => draggable.value?.y, async () => {
|
|
|
+ if (props.config!.fullScreen) return
|
|
|
+ let bottom = window.innerHeight - dialogRef.value!.clientHeight
|
|
|
+ if (draggable.value.y < 0) {
|
|
|
+ draggable.value.y = 0
|
|
|
+ } else if (draggable.value.y > bottom) {
|
|
|
+ draggable.value.y = bottom
|
|
|
+ }
|
|
|
+ dislogStyle.top = draggable.value.y + 'px'
|
|
|
+})
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ await nextTick()
|
|
|
+ if (dialogRef.value === null) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let top = (window.innerHeight * (10 / 100))
|
|
|
+ let left = (window.innerWidth / 2) - (dialogRef.value?.clientWidth / 2);
|
|
|
+
|
|
|
+ draggable.value = useDraggable(dialogHeadRef, {
|
|
|
+ initialValue: {x: left as number, y: top as number},
|
|
|
+ })
|
|
|
+ let zIndex = [...document.all].reduce((r, e) => Math.max(r, +window.getComputedStyle(e).zIndex || 0), 0)
|
|
|
+ dislogStyle.zIndex = zIndex
|
|
|
+
|
|
|
+ if (props.config?.width) {
|
|
|
+ dislogStyle.width = props.config?.width
|
|
|
+ }
|
|
|
+
|
|
|
+ const body = document.querySelector("body");
|
|
|
+ if (body.append) {
|
|
|
+ body.append(dialogRef.value);
|
|
|
+ } else {
|
|
|
+ body.appendChild(dialogRef.value);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+})
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+
|
|
|
+.cy-dialog-enter-active {
|
|
|
+ animation: xing .3s;
|
|
|
+}
|
|
|
+
|
|
|
+.cy-dialog-leave-active {
|
|
|
+ animation: xing .3s reverse;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes xing {
|
|
|
+ 0% {
|
|
|
+ transform: scale(0.5);
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.cy-dialog__v2 {
|
|
|
+ position: absolute;
|
|
|
+ height: max-content;
|
|
|
+ border-radius: 10px;
|
|
|
+
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 4px 8px rgb(0 0 0 / 20%), 0 6px 20px rgb(0 0 0 / 19%);
|
|
|
+
|
|
|
+
|
|
|
+ .cy-dialog__header {
|
|
|
+ width: 100%;
|
|
|
+ position: relative;
|
|
|
+ border-bottom: 1px solid;
|
|
|
+ cursor: move;
|
|
|
+ background-color: white;
|
|
|
+
|
|
|
+ .cy-dialog__title {
|
|
|
+ line-height: 40px;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .cy-dialog__icon {
|
|
|
+ padding: 10px 0;
|
|
|
+ display: flex;
|
|
|
+ position: absolute;
|
|
|
+ width: content-box;
|
|
|
+ top: 0;
|
|
|
+ right: 5px;
|
|
|
+ cursor: default;
|
|
|
+
|
|
|
+ div {
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ padding: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ border-radius: 10px;
|
|
|
+ margin-left: 5px;
|
|
|
+
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ i {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ i {
|
|
|
+ font-size: 12px;
|
|
|
+ color: black;
|
|
|
+ transform: scale(0.8);
|
|
|
+ opacity: 0;
|
|
|
+ transition: opacity .2s;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.cy-dialog__fullScreen {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ margin: 0;
|
|
|
+ border-radius: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.cy-dialog__main {
|
|
|
+ display: flex;
|
|
|
+ height: max-content;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+</style>
|