最終效果
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時直接消失好了~
我們的帶過渡動畫的手風琴摺疊效果就做好啦,效果和文章開頭的圖一樣~
覺得有用的請點個贊,謝謝大家的觀看~轉載請帶本文鏈接