uniapp简单实现一个不定高展开收缩组件

文章介绍了如何在uni-app中利用CSS的transition属性和margin-top来实现内容区域的平滑过渡效果,以达到点击按钮控制内容的出现和消失。在处理过程中,通过设置标题的z-index防止内容上移时遮挡标题,并在组件更新时动态获取内容高度。此方法适用于不支持内置transition组件的微信小程序环境。
摘要由CSDN通过智能技术生成

期望效果

实现思路

效果分析:蓝色区域(以下称为标题)不动,点击按钮,控制粉色区域(以下称为内容)的出现与消失。

思路1:针对“出现&消失”,首先可以考虑使用v-show,配合uni-app的内置组件transition来实现内容展示的过渡效果。但微信小程序不支持transition,所以放弃该方案。

思路2:虽然内置组件transition不能用,但是css里有个transition属性,它可以为元素设置过渡效果。transition: property duration timing-function delay; (这里用前两个就行)

思路分析:

  1. 确定使用css的transition的属性来实现内容的过渡效果,首先确定transition-property。因为内容消失的时候是向上平移,出现的时候是向下平移,所以可以使用margin-top。当内容出现时,其margin-top为0;当内容消失时,其margin-top为(-内容的高度)。(注意:property属性必须过渡前后都有确定的数值!否则过渡不生效)

  1. 标题在内容上方,为了不让内容上移时,遮挡住标题,可以为标题设置z-index。(注意:z-index属性只能在设置了position: relative | absolute | fixed的元素和父元素设置了 display: flex属性的子元素中起作用,在其他元素中是不作用的)

开始动手

展开组件制作

<template>
  <view class="expand-box">
    <view class="title-box">
      <view class="title">
        <slot name="title"></slot>
      </view>
      <view
        class="icon"
        :class="{ right: !expand }"
        @click="handleExpand"
      ></view>
    </view>
    <view
      id="content-box"
      class="content-box"
      :style="{
        marginTop: expand ? 0 + 'px' : -contentHeight + 'px',
      }"
    >
      <slot name="content"></slot>
    </view>
  </view>
</template>

<script setup>
import { ref, getCurrentInstance, onMounted, onBeforeUpdate } from 'vue'

const expand = ref(true)
const contentHeight = ref()
let query

onMounted(() => {
  query = uni
    .createSelectorQuery()
    .in(getCurrentInstance())
    .select('#content-box')
  query
    .boundingClientRect((data) => {
      contentHeight.value = data.height
    })
    .exec()
})

onBeforeUpdate(() => {
  query
    .boundingClientRect((data) => {
      contentHeight.value = data.height
    })
    .exec()
})

function handleExpand() {
  expand.value = !expand.value
}
</script>

<style lang="scss" scoped>
.expand-box {
 /* min-height的值必须有,且需与title-box的height保持一致。*/
 /* 如果不设置min-height,当content-box的margin-top绝对值大于自身height值后,会影响expand-box高度*/
  min-height: 80rpx; 
  overflow: hidden; /* 隐藏上移的内容 */
  margin-bottom: 30rpx;
}
.title-box {
  position: relative;
  z-index: 1;
  height: 80rpx;
  background-color: skyblue;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  .title {
    font-weight: bold;
    font-size: 30rpx;
  }
  .icon {
    width: 40rpx;
    height: 40rpx;
    background-size: cover;
    background-image: url('@/static/icons/expand.png');
    transition: transform 0.8s;
  }
  .right {
    transform: rotate(-90deg);
  }
}
.content-box {
  transition: margin-top 0.8s;
}
</style>

展开组件使用

// 组件需要绑定一个属性,属性名随意,但属性值一定要与content插槽内的内容数量有关
// 目的是为了告诉Expand组件内容发生了变化,需要重新获取内容的高度
<Expand :content="arr.length">
    <template #title> 我是标题 </template>
    <template #content>
        <view v-for=“(item, index) in arr” :key="index">{{item}}</view>
    </template>
</Expand>

<script setup>
import { ref } from 'vue'
const arr =[1,2,3]
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值