最终效果
UI同学让做一个带过渡动画的手风琴折叠效果,点击一个元素展开,其他已展开元素自动收缩,每次最多只有一个元素展开,这是最终效果:
接下来讲我用css实现的思路
一、无过渡动画的手风琴
首先,uniapp做无过渡动画的最容易做了,因为Vue里只要用v-if
或v-show
来控制,判断index是否是当前的子组件就好了。因为我用了组件,我想父组件的事件openDetail
触发能更新子组件的数据,所以我用:ref
来更新子组件的boolean变量isOpen
来触发v-show="isOpen"
,记录lastIndex
来关闭上个展开的子组件,确保每次点击最多只有一个展开。
父组件
<view>
<collapse-item v-for="(item, index) in list" :key="index"
@tap="openDetail(index)" :ref="'collapse'+index"
</collapse-item>
</view>
...
<script>
export default {
data() {
return {
lastIndex: -1;
}
},
methods: {
// 手风琴式收缩展示offer列表
if (index != this.lastIndex && this.lastIndex >= 0) {
this.$refs['collapse'+this.lastIndex][0].isOpen = false;
this.$refs['collapse'+index][0].isOpen = !this.$refs['collapse'+index][0].isOpen;
} else {
this.$refs['collapse'+index][0].isOpen = !this.$refs['collapse'+index][0].isOpen;
}
this.lastIndex = index;
}
}
</script>
子组件collapse-item
<view v-show="isOpen">
<view>专业</view>
<view>均分</view>
<view>入学</view>
</view>
...
export default {
data() {
return {
isOpen: false,
}
},
}
二、有过渡动画的手风琴
现在来做过渡动画,我在做的时候,发现有以下几点需要注意:
1. 不能再用v-if或v-show
过渡动画的css实现大家肯定能想到是transition
,而transition
的动画是基于两个状态的来回变化的,不管是v-if
的增删DOM节点还是v-show的display: none
都是只有一个状态,无法满足前后两个状态,transition
会失效。
2. 用:class动态绑定样式
可以用 :class
的对象语法:class="isOpen ? 'content-open' : 'content-close'"
来动态绑定展开和收起两种状态的样式。
展开状态设置高度height
值,而收起状态设height
为0,两个状态都设置transition
,就能实现过渡动画。
我们来更新一下子组件collapse-item的代码:
<view :class="isOpen ? 'content-open' : 'content-close'">
<view :style="{height: isOpen ? '40rpx' : '0'}">专业</view>
<view :style="{height: isOpen ? '40rpx' : '0'}">均分</view>
<view :style="{height: isOpen ? '40rpx' : '0'}">入学</view>
</view>
...
export default {
data() {
return {
isOpen: false,
}
},
}
...
<style>
.content-open {
height: 180 rpx;
transition: all 0.4s cubic-bezier(0.25, 1.0, 0.25, 1.0);
}
.content-close {
height: 0;
transition: all 0.4s cubic-bezier(0.25, 1.0, 0.25, 1.0);
}
</style>
3. 子元素也要设置transition
写完上面的代码以后,我发现了一个问题,文字出现的比背景颜色快,在背景颜色还没有过渡动画展开完时,文字就已经全出现了,而且文字并没有像我预想一样的也有展开动画效果。
问题虽然不大,但是视觉上给人的体验非常不好,所以我一定要解决。
正当我无比困惑时,我突然想到,是不是transition
属性无法继承?
我就查了一下W3C文档:https://drafts.csswg.org/css-transitions/
果然transition
是inherited:no
,无法继承的。
所以我们子元素也都要设置transition
,才能达到背景颜色和文字同时有过渡动画的展开和收起的效果。
再更新一下子组件的代码:
<view :class="isOpen ? 'content-open' : 'content-close'">
<view :class="isOpen ? 'item-open' : 'item-close'">专业</view>
<view :class="isOpen ? 'item-open' : 'item-close'">均分</view>
<view :class="isOpen ? 'item-open' : 'item-close'">入学</view>
</view>
...
export default {
data() {
return {
isOpen: false,
}
},
}
...
<style>
.content-open {
height: 180 rpx;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.25, 1.0, 0.25, 1.0);
}
.content-close {
height: 0;
transition: all 0.4s cubic-bezier(0.25, 1.0, 0.25, 1.0);
}
.item-open {
height: 40rpx;
transition: all 0.4s cubic-bezier(0.25, 1.0, 0.25, 1.0);
}
.item-close {
opacity: 0;
height: 0;
}
</style>
content-open
里设置overflow: hidden
,展开时文字就不会浮在下一个元素上。
至于我为什么子元素的item-close
不设置transition
呢,因为三行文字先会缩成一行重叠的字再消失,太丑了,大家试试就知道了,所以干脆文字在close时直接消失好了~
我们的带过渡动画的手风琴折叠效果就做好啦,效果和文章开头的图一样~
觉得有用的请点个赞,谢谢大家的观看~转载请带本文链接