104 lines
2.2 KiB
Vue
104 lines
2.2 KiB
Vue
<template>
|
|
<div>
|
|
<slot name="header"></slot>
|
|
</div>
|
|
<Transition
|
|
name="collapse-transition"
|
|
@beforeEnter="beforeEnter"
|
|
@enter="enter"
|
|
@afterEnter="afterEnter"
|
|
@beforeLeave="beforeLeave"
|
|
@leave="leave"
|
|
@afterLeave="afterLeave"
|
|
>
|
|
<div v-if="props.expand">
|
|
<slot name="body"></slot>
|
|
</div>
|
|
</Transition>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, defineProps, type RendererElement } from 'vue';
|
|
|
|
const props = defineProps({
|
|
expand: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
});
|
|
|
|
const beforeEnter = (el: RendererElement) => {
|
|
if (!el.dataset) {
|
|
el.dataset = {};
|
|
}
|
|
if (el.style.height) {
|
|
el.dataset.height = el.style.height;
|
|
}
|
|
el.style.maxHeight = 0;
|
|
};
|
|
const enter = (el: RendererElement) => {
|
|
requestAnimationFrame(() => {
|
|
el.dataset.oldOverflow = el.style.overflow;
|
|
if (el.dataset.height) {
|
|
el.style.maxHeight = el.dataset.height;
|
|
} else if (el.scrollHeight !== 0) {
|
|
el.style.maxHeight = `${el.scrollHeight}px`;
|
|
} else {
|
|
el.style.maxHeight = 0;
|
|
}
|
|
el.style.overflow = 'hidden';
|
|
});
|
|
};
|
|
const afterEnter = (el: RendererElement) => {
|
|
el.style.maxHeight = '';
|
|
el.style.overflow = el.dataset.oldOverflow;
|
|
};
|
|
const beforeLeave = (el: RendererElement) => {
|
|
if (!el.dataset) {
|
|
el.dataset = {};
|
|
}
|
|
el.dataset.oldOverflow = el.style.overflow;
|
|
el.style.maxHeight = `${el.scrollHeight}px`;
|
|
el.style.overflow = 'hidden';
|
|
};
|
|
const leave = (el: RendererElement) => {
|
|
if (el.scrollHeight !== 0) {
|
|
el.style.maxHeight = 0;
|
|
}
|
|
};
|
|
const afterLeave = (el: RendererElement) => {
|
|
el.style.maxHeight = '';
|
|
el.style.overflow = el.dataset.oldOverflow;
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.v-enter-active,
|
|
.v-leave-active {
|
|
transition: opacity 0.5s ease;
|
|
}
|
|
|
|
.v-enter-from,
|
|
.v-leave-to {
|
|
opacity: 0;
|
|
}
|
|
|
|
.collapse-transition {
|
|
&-enter-from,
|
|
&-leave-to {
|
|
opacity: 0;
|
|
}
|
|
|
|
&-enter-to,
|
|
&-leave-from {
|
|
opacity: 1;
|
|
}
|
|
|
|
&-enter-active,
|
|
&-leave-active {
|
|
transition:
|
|
max-height 0.3s cubic-bezier(0.5, 0.05, 0.5, 0.95),
|
|
opacity 0.3s cubic-bezier(0.5, 0.05, 0.5, 0.95);
|
|
}
|
|
}
|
|
</style> |