uni-app官方uni-collapse组件默认无过渡动画,需手动实现:推荐用max-height+transition(设足够大值如500px)或transform:scaleY()+transition(安卓更稳),注意动态计算高度、唯一key、transitionend事件处理。

uni-app里collapse组件不带动画?别用它
uni-app官方uni-collapse组件默认没有过渡动画,展开/收起是瞬时切换的。这不是你配置错了,是它压根没实现transition逻辑——源码里连height的动态计算和CSS过渡都没绑定。
真实项目里要平滑伸缩,得自己控制height或用transform: scaleY(),配合overflow: hidden和transition。直接套用uni-collapse只会白忙活。
- 别在
uni-collapse-item上加style="transition: height 0.3s"——无效,因为高度是auto,CSS无法过渡auto - 别试图用
v-show配opacity模拟——用户要的是“高度伸缩”,不是淡入淡出 - 真要用官方组件,只能自己fork后改源码,成本远高于手写一个轻量
CollapseItem
用max-height + transition做最简可靠方案
这是兼容性最好、逻辑最直白的做法:把内容包进一个固定max-height容器,靠CSS过渡控制“看起来”的伸缩效果。
关键不是设height,而是用max-height从0到一个足够大的值(比如500px),并确保内容不会溢出。
<view class="collapse-item">
<view class="header" @click="toggle">{{ title }}</view>
<view class="content" :class="{ 'expanded': expanded }">{{ content }}</view>
</view>CSS里这样写:
.content {
overflow: hidden;
max-height: 0;
transition: max-height 0.3s ease-in-out;
}
.content.expanded {
max-height: 500px; /* 要大于内容实际高度 */
}-
max-height值不能写auto,否则过渡失效 - 如果内容高度差异大(比如图文混排+长段落),
500px可能不够,可动态计算:this.$nextTick(() => this.maxHeight = $refs.content.scrollHeight + 'px') - 安卓WebView对
max-height过渡支持不稳定,若遇到卡顿,换transform: scaleY()方案
安卓下transform: scaleY()更稳,但要注意布局塌陷
当max-height在某些安卓机型上跳帧或闪动时,改用transform是更底层的解法——它走GPU加速,且不触发重排。
原理是让内容容器绕顶部中点缩放,scaleY(0)→scaleY(1),同时用origin-top保证从上往下展开。
.content {
transform-origin: top;
transform: scaleY(0);
transition: transform 0.3s ease-in-out;
}
.content.expanded {
transform: scaleY(1);
}- 必须加
transform-origin: top,否则默认居中缩放,会“从中间炸开” - 缩放后父容器高度不会自动适应,会导致下方元素位置错乱——得给
.content外层加height占位,或用visibility: hidden配合height手动控制 - 如果内容里有
position: absolute元素,缩放会影响其定位基准,需额外处理
多个折叠项联动时,ref和key容易被忽略
列表渲染多个CollapseItem时,如果共用同一个expanded状态,点一个全开——这显然不对。得为每个项维护独立状态,但更隐蔽的问题在DOM更新时机。
- 用
v-for渲染时,必须给每个item加唯一:key,否则折叠/展开后顺序错乱、动画错位 - 动态计算
max-height时,ref要绑定在内容view上,且必须等v-if插入DOM后才调$refs.content.scrollHeight,否则取到0 - 不要在
watch里直接改max-height样式——uni-app的style响应式更新有延迟,优先用class切换控制
复杂点在于:动画是否完成、内容是否加载完毕、父容器是否已渲染,这三个时机稍一错位,就出现“闪一下再展开”或者“只展一半”。真要稳,就得在transitionend事件里做清理,而不是依赖v-model或watch。


















