Files
ks-app-employment-service/components/CollapseTransition/CollapseTransition.vue

93 lines
1.9 KiB
Vue
Raw Normal View History

2025-03-28 15:19:42 +08:00
<!-- CollapseTransition.vue -->
<template>
<view :style="wrapStyle" class="collapse-wrapper">
<view ref="contentRef" class="content-inner">
<slot />
</view>
</view>
</template>
<script setup>
import { ref, watch, nextTick } from 'vue';
const props = defineProps({
show: Boolean,
duration: {
type: Number,
default: 300,
},
});
const wrapStyle = ref({
height: '0rpx',
opacity: 0,
overflow: 'hidden',
transition: `all ${props.duration}ms ease`,
});
const contentRef = ref(null);
// 获取高度(兼容 H5 + 小程序)
function getContentHeight() {
return new Promise((resolve) => {
const query = uni.createSelectorQuery().in(this ? this : undefined);
query
.select('.content-inner')
.boundingClientRect((data) => {
resolve(data?.height || 0);
})
.exec();
});
}
// 动画执行
async function expand() {
const height = await getContentHeight();
wrapStyle.value = {
height: height + 'px',
opacity: 1,
overflow: 'hidden',
transition: `all ${props.duration}ms ease`,
};
setTimeout(() => {
wrapStyle.value.height = 'auto';
}, props.duration);
}
async function collapse() {
const height = await getContentHeight();
wrapStyle.value = {
height: height + 'px',
opacity: 1,
overflow: 'hidden',
transition: 'none',
};
// 等待下一帧开始收起动画
await nextTick();
requestAnimationFrame(() => {
wrapStyle.value = {
height: '0rpx',
opacity: 0,
overflow: 'hidden',
transition: `all ${props.duration}ms ease`,
};
});
}
watch(
() => props.show,
(val) => {
if (val) expand();
else collapse();
}
);
</script>
<style scoped>
.collapse-wrapper {
width: 100%;
}
</style>