| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- <template>
- <view
- :id="id"
- class="nana-collapse-box"
- :style="{
- display: realOpenState ? '' : 'none',
- height: animDuration > 0 && targetHeight >= 0 ? `${targetHeight}px` : undefined,
- transition: animDuration > 0 ? `height ${animDuration}ms ease-in-out` : undefined,
- }"
- >
- <slot />
- </view>
- </template>
- <script setup lang="ts">
- import { RandomUtils } from '@imengyu/imengyu-utils';
- import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue';
- export interface CollapseBoxProps {
- /**
- * 开启状态
- */
- open: boolean;
- /**
- * 动画时长(ms),为0时禁用动画
- * @default 300
- */
- animDuration?: number;
- /**
- * 名称,用于唯一标识
- */
- name?: string;
- }
- const id = computed(() => `nana-collapse-box-${props.name}-${RandomUtils.genNonDuplicateIDHEX(16)}`);
- const props = withDefaults(defineProps<CollapseBoxProps>(), {
- animDuration: 300,
- });
- const realOpenState = ref(false);
- const targetHeight = ref(0);
- const instance = getCurrentInstance();
- let isAnimWorking = false;
- watch(() => props.open, (newVal) => {
- if (props.animDuration <= 0) {
- realOpenState.value = newVal;
- return;
- }
- if (isAnimWorking)
- return;
- if (newVal) {
- realOpenState.value = true;
- targetHeight.value = -1;
- isAnimWorking = true;
- nextTick(() => {
- uni.createSelectorQuery()
- // #ifdef MP
- .in(instance)
- // #endif
- .select(`#${id.value}`)
- .boundingClientRect(rect => {
- const ref = rect instanceof Array ? rect[0] : rect;
- const height = ref?.height || 500;
- targetHeight.value = 0;
- setTimeout(() => {
- targetHeight.value = height;
- setTimeout(() => {
- isAnimWorking = false;
- }, props.animDuration);
- }, 10);
- })
- .exec()
- })
- } else {
- isAnimWorking = true;
- targetHeight.value = 0;
- setTimeout(() => {
- realOpenState.value = false;
- isAnimWorking = false;
- }, props.animDuration);
- }
- });
- </script>
- <style lang="scss">
- .nana-collapse-box {
- overflow: hidden;
- will-change: height;
- }
- </style>
|