前端實戰(zhàn):使用CSS3實現類在線直播的隊列動畫
之前在群里有個朋友問了這樣一個問題, 就是如何在小程序中實現類似直播平臺的用戶上線時的隊列動畫? 作為一名前端工程師, 解決方案無非以下2種:
- 使用javascript根據條件來控制元素的樣式實現隊列動畫
- 用純css3配合數據驅動模型來實現.
大家都知道在現代的Web開發(fā)中, 我們能使用Css實現的效果盡量不要用Js, 所以我們應該優(yōu)先考慮用Css3來實現,但是我們要結合數據流才能實現真正的隊列動畫, 所以我們可以利用MVVM框架便捷的數據驅動模型來控制動畫的走向。
又由于動畫的核心在于Css3, 所以在小程序或者是Vue/React中實現其實原理都是相似的, 大家不必擔心技術棧的問題。以下是實現后的效果圖:
如果以上gif無法訪問, 可以查看下面的靜態(tài)圖:
其實這種效果在很多地方都用到, 比如B站的彈幕, 某音樂平臺直播的粉絲上線動畫, 某音的直播等等, 而在Web端, 我們又能怎么實現它呢? 接下來筆者將帶大家一步步實現這樣的動畫效果.
正文
要想實現上面的動畫效果, 我們需要先分析一下動畫, 上圖的動畫結構如下:
動畫一共分為以下兩個過程:
- 用戶進入動畫
- 用戶淡出動畫
還有一個細節(jié)就是不管進入多少個用戶, 都是從同一個位置進入的, 此時上一個用戶位置會上移,如下圖所示:
所以要想實現這樣的效果最好的方式就是使用定位,比如絕對定位(absolute)或者固定定位(fixed). 并設置其bottom值, 如下代碼所示:
- .animateWrap {
- position: absolute;
- bottom: 40%;
- left: 12px;
- }
以上位置信息僅供參考,具體數值可根據自身需求來更改.設置bottom的好處是容器的子元素一旦增加, 會自動將上一個元素頂上去, 所以不需要我們手動去設置其偏移值.
實現進入動畫
我們要想實現上圖的用戶進入動畫, 可以使用Css3的過渡動畫transition,也可以使用animation動畫, 由于使用場景的便捷性這里我們采用animation動畫, 首先我們先寫一下dom結構:
- <div className={styles.animateWrap}>
- <div className={styles.animate} key={item}><div className={styles.tx}><img src={tx} alt=""/></div><span>李老師上線</span></div>
- <div className={styles.animate} key={item}><div className={styles.tx}><img src={tx} alt=""/></div><span>李老師上線</span></div>
- <div className={styles.animate} key={item}><div className={styles.tx}><img src={tx} alt=""/></div><span>李老師上線</span></div>
- </div>
以上代碼表示創(chuàng)建了一個動畫容器, 并且添加了2個用戶, 這里我們定義一下關鍵動畫如下:
- .animate {
- margin-bottom: 10px;
- border-radius: 20px;
- background-color: rgba(0,0,0, .3);
- animation: moveIn 1.2s;
- }
- @keyframes moveIn {
- 0% {
- transform: translateX(calc(-100% - 12px));
- }
- 100% {
- transform: translateX(0);
- }
- }
以上即實現了元素向右移入的動畫, 但是此時我們看到的動畫是同時出現的, 我們要應用到真實場景中, 一定是通過socket或者通過輪循拿到的異步數據, 因此我們可以使用setInterval來模擬這一過程. 還有一個細節(jié)是我們動畫里最多只完整展示2條用戶數據, 多余的數據會漸出隱藏, 因此我們需要對數據進行截流, 代碼如下:
- const [user, setUser] = useState<Array<string>>([])
- useEffect(() => {
- let MAX_USER_COUNT = 2;
- let timer = setInterval(() => {
- setUser(prev => {
- prev.push(Date.now() + '')
- if(prev.length > MAX_USER_COUNT + 1){
- prev.shift()
- return [...prev]
- }else {
- return [...prev]
- }
- })
- }, 2000)
- }, [])
變量MAX_USER_COUNT用來控制最大展示的用戶數,可以根據實際需求更改, setUser里面的邏輯即為截流邏輯, 當用戶數超過指定的最大值時, 會將頭部元素刪除。
以上即完成了數據流轉的過程, 我們還需要處理的是用戶漸出邏輯和動畫.我們先看看漸出的animation:
- @keyframes moveOut {
- 0% {
- opacity: 1;
- }
- 100% {
- opacity: 0;
- }
- }
其實動畫并不難, 我們需要控制的是如何給頭部元素動態(tài)的添加這個動畫, 此時我們最好的方案是通過類名, 即當滿足漸出的條件時, 我們需要給漸出的元素動態(tài)設置漸出類名, 條件如下:
- user.length > MAX_USER_COUNT && i === 0
以上條件指的是當用戶數超過最大展示用戶數并且當且元素為頭部元素時, 那么我們只需要根據這個條件來動態(tài)設置類名即可:
- { user.map((item, i) => {
- return <div
- className={
- classnames(styles.animate,
- user.length > 2 && i === 0 ? styles.hidden : '')
- }
- key={item}
- >
- <div className={styles.tx}>
- <img src={tx} alt=""/>
- </div>
- <span>李老師{item}上線</span>
- </div>
- })
- }
css代碼如下:
- hidden { opacity: 0; animation: moveOut 1.2s;}
通過以上步驟我們就實現了一個完整的類在線直播的隊列動畫, 動畫完整css代碼如下, 感興趣的盆友可以學習參考一下:
- animateWrap {
- position: absolute;
- bottom: 40%;
- left: 12px;
- .animate {
- margin-bottom: 10px;
- border-radius: 20px;
- background-color: rgba(0,0,0, .3);
- animation: moveIn 1.2s;
- .tx {
- display: inline-block;
- width: 36px;
- height: 36px;
- border-radius: 50%;
- overflow: hidden;
- vertical-align: middle;
- margin-right: 10px;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- }
- span {
- margin-right: 12px;
- line-height: 36px;
- font-size: 14px;
- color: #fff;
- }
- }
- .hidden {
- opacity: 0;
- animation: moveOut 1.2s;
- }
- @keyframes moveIn {
- 0% {
- transform: translateX(calc(-100% - 12px));
- }
- 100% {
- transform: translateX(0);
- }
- }
- @keyframes moveOut {
- 0% {
- opacity: 1;
- }
- 100% {
- opacity: 0;
- }
- }
- }
本文轉載自微信公眾號「趣談前端」,可以通過以下二維碼關注。轉載本文請聯(lián)系趣談前端公眾號。