微信小程序純CSS實(shí)現(xiàn)無(wú)限彈幕滾動(dòng)效果
啥也不說(shuō),先上效果圖

實(shí)現(xiàn)背景
產(chǎn)品: 我們需要一個(gè)彈幕滾動(dòng)效果,類(lèi)似于微博熱搜那種實(shí)時(shí)評(píng)論,但是我們的數(shù)據(jù)是固定的20條,你讓他一直循環(huán)滾動(dòng)
我 好的(os:要求真多)
實(shí)現(xiàn)思路
你不是說(shuō)要微博熱搜彈幕那種效果嗎?這好辦啊,馬上去微博看熱搜(又看到那么多塌房的的明星),看了幾十分鐘,表面上是多研究研究,實(shí)則上班期間光明正大的摸魚(yú),感覺(jué)真好??!
- 先看看微博的效果
分析一下,有以下幾個(gè)功能點(diǎn)
- 彈幕實(shí)時(shí)更新
- 從右到左勻速運(yùn)動(dòng)
- 點(diǎn)擊某一個(gè)彈幕跳轉(zhuǎn)到詳情,返回時(shí)繼續(xù)移動(dòng)
一共三個(gè)功能點(diǎn),對(duì)比我的需求只有一個(gè)功能點(diǎn)相差,我只需要把彈幕實(shí)時(shí)更新改成彈幕循環(huán)滾動(dòng)。
如何實(shí)現(xiàn)循環(huán)的感覺(jué)呢?
如果要實(shí)現(xiàn)一個(gè)循環(huán)的感覺(jué)就必須要把數(shù)組拷貝一份,把他們一排排列,然后這樣子讓他去滾動(dòng),當(dāng)滾動(dòng)結(jié)尾的時(shí)候,展示第二個(gè)拷貝數(shù)組的開(kāi)頭。animate動(dòng)畫(huà)幀的編寫(xiě)就改變transform:translateX的值,從0到單個(gè)數(shù)組所渲染的dom長(zhǎng)度,第一次的動(dòng)畫(huà)執(zhí)行完成后,剛好是第二個(gè)拷貝數(shù)組的開(kāi)頭,然后又讓動(dòng)畫(huà)幀執(zhí)行從0到單個(gè)數(shù)組所渲染的dom長(zhǎng)度,由于每一次動(dòng)畫(huà)執(zhí)行完剛好是第二個(gè)拷貝數(shù)組的開(kāi)頭,所以執(zhí)行第二次動(dòng)畫(huà)時(shí)不會(huì)有閃動(dòng)的感覺(jué)
如何實(shí)現(xiàn)動(dòng)畫(huà)執(zhí)行完又繼續(xù)執(zhí)行呢?
設(shè)置animation-iteration-count: infinite;,循環(huán)執(zhí)行,這樣子就會(huì)無(wú)限的從0到單個(gè)數(shù)組所渲染的dom長(zhǎng)度,無(wú)限的循環(huán)套娃,就會(huì)有循環(huán)滾動(dòng)的感覺(jué)了,大概圖如下

代碼實(shí)現(xiàn)
- 先拷貝一份數(shù)組讓他們一排排列,注意最外層的容器需要設(shè)置
overflow: hidden
<view class="z-bullet-test">
<view class="z-list">
<view class="z-container">
<view class="z-single" wx:for="{{10}}" wx:key="index">
{{index}}
</view>
</view>
<view class="z-container">
<view class="z-single" wx:for="{{10}}" wx:key="index">
{{index}}
</view>
</view>
</view>
</view>
.z-bullet-test {
width: 690rpx;
height: 88rpx;
display: flex;
align-items: center;
background-color: saddlebrown;
margin: 0 auto;
margin-top: 40rpx;
overflow: hidden;
}
.z-container {
display: flex;
flex-wrap: nowrap;
}
.z-single {
padding: 10rpx 40rpx;
color: white;
background-color: cadetblue;
margin-right: 20rpx;
}
.z-list {
display: flex;
flex-wrap: nowrap;
}
效果如下

- 讓外層的容器滾動(dòng)起來(lái),只需要給
z-list添加動(dòng)畫(huà)即可
.z-list {
display: flex;
flex-wrap: nowrap;
animation: rowScrollTest 2s linear infinite;
}
@keyframes rowScrollTest {
0% {
/* 為0時(shí),ios會(huì)閃動(dòng) */
transform: translateX(1);
}
100% {
transform: translateX(-433.85px); // 單個(gè)數(shù)組所渲染的dom長(zhǎng)度
}
}
效果如下

通過(guò)以下幾句代碼,并且沒(méi)有使用任何的js代碼就把無(wú)限循環(huán)滾動(dòng)實(shí)現(xiàn)好了,是不是覺(jué)得事情到這兒結(jié)束了呢???
并沒(méi)有
如何動(dòng)態(tài)計(jì)算單個(gè)數(shù)組所渲染的dom長(zhǎng)度
上面實(shí)現(xiàn)的代碼中,對(duì)于單個(gè)數(shù)組所渲染的dom長(zhǎng)度是通過(guò)開(kāi)發(fā)者工具找到dom長(zhǎng)度,并在代碼中寫(xiě)死的,但是在開(kāi)發(fā)中你并不能確定這個(gè)長(zhǎng)度到底為多少,這個(gè)時(shí)候我們需要去動(dòng)態(tài)獲取這個(gè)dom長(zhǎng)度
這個(gè)時(shí)候就有同學(xué)說(shuō)了,那還不簡(jiǎn)單直接通過(guò)js去獲取dom長(zhǎng)度不就可以了嗎?
想法很不錯(cuò),先給你點(diǎn)個(gè)贊,但是重點(diǎn)來(lái)了?。?!注意看,通過(guò)js獲取dom長(zhǎng)度可以得到一個(gè)長(zhǎng)度變量,但是你如何動(dòng)態(tài)賦值給@keyframes動(dòng)畫(huà)幀呢??
@keyframes rowScrollTest {
0% {
/* 為0時(shí),ios會(huì)閃動(dòng) */
transform: translateX(1);
}
100% {
transform: translateX(domWidth); // 單個(gè)數(shù)組所渲染的dom長(zhǎng)度
}
}
思考一下?這個(gè)domWidth應(yīng)該如何去動(dòng)態(tài)的賦值呢?
動(dòng)態(tài)賦值動(dòng)畫(huà)幀中的css參數(shù)
遇到這個(gè)問(wèn)題時(shí),感覺(jué)有點(diǎn)奇怪,這個(gè)動(dòng)態(tài)的賦值一般是給css屬性,如width,height,還沒(méi)有給動(dòng)畫(huà)幀中的css屬性動(dòng)態(tài)賦值過(guò),
于是照著給css屬性動(dòng)態(tài)賦值的方法,我把@keyframes動(dòng)畫(huà)幀函數(shù)先寫(xiě)到了行內(nèi)style上,并把css中的@keyframes動(dòng)畫(huà)幀函數(shù)刪除
<view class="z-list" style="@keyframes rowScrollTest {0% { transform: translateX(1); } 100% { transform: translateX(-433.85px); }}">
<!-- 數(shù)組內(nèi)容 -->
</view>
滿(mǎn)心歡喜的打開(kāi)開(kāi)發(fā)者工具,一看~~ 嘿! 動(dòng)都不動(dòng)了
原因是因?yàn)閟tyle屬性只能識(shí)別出css的屬性名,我在這里寫(xiě)的動(dòng)畫(huà)幀函數(shù),在它看來(lái)就是一串沒(méi)有用的字符串,所以就根本不會(huì)編譯成css的動(dòng)畫(huà)幀函數(shù),就肯定不會(huì)有作用了
如何解決呢?
傳統(tǒng)的給css屬性動(dòng)態(tài)賦值的方法走不通,應(yīng)該怎么辦呢?99%解決問(wèn)題的辦法:點(diǎn)開(kāi)goole然后再輸入欄輸入這個(gè)問(wèn)題,按下enter鍵,然后就去瘋狂的尋找就可以了。
經(jīng)過(guò)一番查找,嘿還真找到了一個(gè)東西,css自定義屬性(變量),這是個(gè)啥呢?
MDN解釋?zhuān)?strong>自定義屬性(有時(shí)候也被稱(chēng)作CSS 變量或者級(jí)聯(lián)變量)是由 CSS 作者定義的,它包含的值可以在整個(gè)文檔中重復(fù)使用。由自定義屬性標(biāo)記設(shè)定值(比如: --main-color: black; ),由 var() 函數(shù)來(lái)獲取值(比如: color: var(--main-color);)復(fù)雜的網(wǎng)站都會(huì)有大量的 CSS 代碼,通常也會(huì)有許多重復(fù)的值。
那我們是不是可以動(dòng)態(tài)賦值給這個(gè)變量,并在css代碼的@keyframes動(dòng)畫(huà)幀函數(shù)中去使用這個(gè)變量的值,當(dāng)作translateX的值呢,立馬試一下
<view class="z-list" style="--domWidth--:-433.85px;">
<!-- 數(shù)組內(nèi)容 -->
</view>
@keyframes rowScrollTest {
0% {
/* 為0時(shí),ios會(huì)閃動(dòng) */
transform: translateX(1);
}
100% {
transform: translateX(var(--domWidth--)); // 單個(gè)數(shù)組所渲染的dom長(zhǎng)度
}
}
激動(dòng)的打開(kāi)開(kāi)發(fā)者工具,見(jiàn)證奇跡的時(shí)刻到來(lái)了?。。。。。。。?! 它動(dòng)了,它在瘋狂的滾動(dòng)著
接下來(lái)是不是只需要將-433.85改成js獲取的單個(gè)數(shù)組所渲染的dom長(zhǎng)度就可以了呢?,于是我滿(mǎn)心歡喜的去寫(xiě)js代碼了,先定義一個(gè)變量domWidth: 0,然后再去onLoad中去獲取z-container的長(zhǎng)度并賦值給domWidth,動(dòng)態(tài)的獲取單個(gè)數(shù)組所渲染的dom長(zhǎng)度并賦值給@keyframes動(dòng)畫(huà)幀函數(shù),就大功告成了?。。?strong>其實(shí)并沒(méi)有,不要看到這兒就不看了!)
<view class="z-list" style="--domWidth--:-{{domWidth}}px;">
<!-- 數(shù)組內(nèi)容 -->
</view>
data: {
domWidth: 0
},
onLoad () {
wx.createSelectorQuery()
.selectAll(".z-container")
.boundingClientRect((res) => {
this.setData({ domWidth: res[0].width });
})
.exec();
}
這個(gè)時(shí)候我輕松的點(diǎn)開(kāi)開(kāi)發(fā)者工具,心里想著這個(gè)問(wèn)題被我輕松解決掉了,還剩很多開(kāi)發(fā)時(shí)間,可以去摸魚(yú)了,但是它不動(dòng)了,一點(diǎn)都不動(dòng)了!
為什么呢? 我立馬點(diǎn)開(kāi)控制臺(tái),找到了這個(gè)變量的值,發(fā)現(xiàn)他是有值的,說(shuō)明問(wèn)題不出在js獲取長(zhǎng)度,
我仔細(xì)一想瞬間明白了 domWidth的值默認(rèn)為0,animation屬性會(huì)在被渲染出來(lái)時(shí)立即執(zhí)行,這個(gè)時(shí)候的domWidth還為0,動(dòng)畫(huà)幀函數(shù)就相當(dāng)于是從0到0,肯定就不會(huì)滾動(dòng)了,你可以把domWidth隨便設(shè)置一個(gè)初始值,你就會(huì)發(fā)現(xiàn)它會(huì)動(dòng)了
那為什么css屬性為0時(shí),動(dòng)態(tài)設(shè)置會(huì)變化呢? 我覺(jué)得是因?yàn)槲⑿判〕绦虮旧韺?duì)于setData這個(gè)函數(shù),根據(jù)改變的data去進(jìn)行重新渲染時(shí),就沒(méi)有包含對(duì)**css自定義屬性(變量)** 的對(duì)比,所以會(huì)導(dǎo)致渲染失效,這個(gè)值一直都是初始值
解決animation執(zhí)行時(shí)domWidth為0的問(wèn)題
這個(gè)時(shí)候有一個(gè)簡(jiǎn)單的解決辦法
- 先判斷如果
domWidth為0,就再渲染一個(gè)由這個(gè)數(shù)組循環(huán)成的靜止dom,并不渲染下面兩個(gè)數(shù)組組成的滾動(dòng)彈幕dom - 然后去獲取這個(gè)靜止dom的長(zhǎng)度,獲取完成了之后,再去渲染下面的滾動(dòng)彈幕dom,并把靜止dom給銷(xiāo)毀掉
- 那么當(dāng)
animation在初始化執(zhí)行時(shí),domWidth的長(zhǎng)度就已經(jīng)是單個(gè)數(shù)組所渲染的dom長(zhǎng)度,就可以順利的去執(zhí)行動(dòng)畫(huà)了
<view class="z-bullet-test">
<block wx:if="{{domWidth === 0}}">
<view class="z-container">
<view class="z-single" wx:for="{{10}}" wx:key="index">
{{index}}
</view>
</view>
</block>
<block wx:else>
<view class="z-list" style="--domWidth--:-{{domWidth}}px;">
<view class="z-container">
<view class="z-single" wx:for="{{10}}" wx:key="index">
{{index}}
</view>
</view>
<!-- -->
<view class="z-container">
<view class="z-single" wx:for="{{10}}" wx:key="index">
{{index}}
</view>
</view>
</view>
</block>
</view>
這樣子就真的大功告成了??!

如何實(shí)現(xiàn)多行彈幕滾動(dòng)?
多行彈幕滾動(dòng)的話,你就多復(fù)制幾行就可以了,并且可以給每一行設(shè)置一個(gè)animation-delay屬性,讓他們不要同時(shí)執(zhí)行animation,去岔開(kāi)時(shí)間來(lái)執(zhí)行,實(shí)現(xiàn)一個(gè)比較亂的彈幕效果。
如何實(shí)現(xiàn)動(dòng)畫(huà)的停止與開(kāi)始呢?
對(duì)于一個(gè)循環(huán)動(dòng)畫(huà),你如果要?jiǎng)討B(tài)的設(shè)置它開(kāi)始或停止,可以通過(guò)animation-play-state屬性設(shè)置running或paused來(lái)設(shè)置動(dòng)畫(huà)的開(kāi)始或停止
總結(jié)
這篇文章,我把自己對(duì)于實(shí)現(xiàn)一個(gè)無(wú)限彈幕滾動(dòng)需求的過(guò)程一一描述了一遍,把自己遇到的問(wèn)題和思考的過(guò)程通過(guò)文字表述了出來(lái),寫(xiě)的可能不是很好,希望可以勉勵(lì)自己的同時(shí)也能幫助到看到這篇文章的朋友,如果你覺(jué)得我的廢話太多,可以直接gitee地址去復(fù)制代碼自己看一下,實(shí)現(xiàn)的代碼量很少,也比較簡(jiǎn)單。
到此這篇關(guān)于微信小程序純CSS實(shí)現(xiàn)無(wú)限彈幕滾動(dòng)效果的文章就介紹到這了,更多相關(guān)CSS彈幕滾動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!
相關(guān)文章

css scroll-snap控制滾動(dòng)元素的實(shí)現(xiàn)
本文主要介紹了css scroll-snap控制滾動(dòng)元素的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)2023-02-22- 這篇文章介紹了使用CSS設(shè)置滾動(dòng)條樣式,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-12-20
這篇文章主要介紹了CSS如何完成視差滾動(dòng)效果,幫助大家更好的理解和學(xué)習(xí)使用CSS,感興趣的朋友可以了解下2021-04-27CSS實(shí)現(xiàn)移動(dòng)端橫向滾動(dòng)導(dǎo)航條(PC端也適用)
這篇文章主要介紹了CSS實(shí)現(xiàn)移動(dòng)端橫向滾動(dòng)導(dǎo)航條(PC端也適用),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編2021-03-17CSS實(shí)現(xiàn)滾動(dòng)高度自動(dòng)變小的粘滯效果實(shí)現(xiàn)思路
粘滯效果是網(wǎng)頁(yè)設(shè)計(jì)中常見(jiàn)的特效之一,在這篇文章中,我們介紹了如何使用JavaScript監(jiān)聽(tīng)窗口滾動(dòng)事件,并根據(jù)滾動(dòng)高度和下一個(gè)區(qū)域的高度來(lái)控制導(dǎo)航欄的表現(xiàn)方式,本文結(jié)合2023-06-13

