uniapp实现带过渡动画的手风琴折叠样式

最终效果

UI同学让做一个带过渡动画的手风琴折叠效果,点击一个元素展开,其他已展开元素自动收缩,每次最多只有一个元素展开,这是最终效果:
在这里插入图片描述
接下来讲我用css实现的思路

一、无过渡动画的手风琴

首先,uniapp做无过渡动画的最容易做了,因为Vue里只要用v-ifv-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/

在这里插入图片描述
果然transitioninherited: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时直接消失好了~

我们的带过渡动画的手风琴折叠效果就做好啦,效果和文章开头的图一样~

觉得有用的请点个赞,谢谢大家的观看~转载请带本文链接

猜你喜欢

转载自blog.csdn.net/sriting/article/details/106111020
今日推荐