React實(shí)現(xiàn)歌詞滾動(dòng)效果(跟隨音樂播放時(shí)間滾動(dòng))
首先給audio綁定更新時(shí)間事件
const updateTime = e => { console.log(e.target.currentTime) setCurrentTime(e.target.currentTime); }; <audio src={currentSong.url} ref={audio} onCanPlay={ready} onEnded={end} onTimeUpdate={updateTime} ></audio>
當(dāng)歌曲播放時(shí)間改變的時(shí)候會(huì)觸發(fā)updateTime事件,如下所示
歌詞json格式
[ { "time": 2, "content": "采樣曲:願(yuàn)い~あの頃のキミへ~", "contents": [ "采樣曲:願(yuàn)い~あの頃のキミへ~" ] }, { "time": 12, "content": "中文填詞:一只然", "contents": [ "中文填詞:一只然" ] }, { "time": 15, "content": "OP(原屬詞曲版權(quán)公司):テレビ?xùn)|京ミュージック 東京電視臺(tái)音樂", "contents": [ "OP(原屬詞曲版權(quán)公司):テレビ?xùn)|京ミュージック 東京電視臺(tái)音樂" ] }, { "time": 19, "content": "本作品經(jīng)過原詞曲作者以及版權(quán)公司授權(quán)", "contents": [ "本作品經(jīng)過原詞曲作者以及版權(quán)公司授權(quán)" ] }, ...... ]
接下來就是根據(jù)當(dāng)前的播放時(shí)間顯示歌詞高亮,給歌詞綁定高亮放大樣式
.highlight { color: $theme-color; font-weight: $font-weight-bold; font-size: 16px !important; }
// 使用Redux的useSelector獲取當(dāng)前播放時(shí)間 const currentTime = useSelector(state => state.musicReducer.currentTime); // 使用React的useMemo優(yōu)化性能,只有當(dāng)currentTime變化時(shí),才會(huì)重新計(jì)算time的值 const time= useMemo(() => { return currentTime; },[currentTime]); // updateTime函數(shù)用于更新當(dāng)前歌詞的索引 const updateTime = e => { // 在所有歌詞中找到第一個(gè)時(shí)間大于當(dāng)前播放時(shí)間的歌詞,其前一個(gè)歌詞就是當(dāng)前應(yīng)該顯示的歌詞 const currentLyricIndex = lyric.findIndex((lyricItem, index) => { // 判斷是否是最后一項(xiàng)歌詞,如果是,下一項(xiàng)歌詞的時(shí)間設(shè)為無窮大 const isLastItem = index === lyric.length - 1; const nextLyricTime = isLastItem ? Infinity : lyric[index + 1].time; // 如果當(dāng)前播放時(shí)間在當(dāng)前歌詞和下一條歌詞的時(shí)間之間,說明當(dāng)前歌詞應(yīng)該被顯示 return time >= lyricItem.time && time < nextLyricTime; }); // 更新當(dāng)前歌詞的索引 setCurrentLyricIndex(currentLyricIndex); }; // 使用React的useEffect在time變化時(shí),調(diào)用updateTime函數(shù),更新當(dāng)前歌詞的索引 useEffect(() => { updateTime() }, [time]);
當(dāng)time
發(fā)生變化時(shí),調(diào)用updateTime
函數(shù)來更新當(dāng)前歌詞的索引currentLyricIndex。確保在歌曲播放過程中,歌詞隨著時(shí)間的推移而更新。
最后,實(shí)現(xiàn)歌詞滾動(dòng)的效果
創(chuàng)建 scrollRef
:
const scrollRef = useRef();
使用 useRef
創(chuàng)建了一個(gè) scrollRef
,用于引用 Scroll 組件的實(shí)例。
使用 useEffect
進(jìn)行歌詞滾動(dòng):
useEffect(() => { // 模擬異步加載歌詞 // 假設(shè)你要滾動(dòng)到的歌詞元素有一個(gè)特定的類名 ".lyric-item.highlight" const selector = '.lyric-item.highlight'; // 調(diào)用 Scroll 組件的 scrollToElement 方法 if (scrollRef.current) { scrollRef.current.scrollToElement(selector, 500); // 第二個(gè)參數(shù)是滾動(dòng)時(shí)間,可以根據(jù)需要調(diào)整 } }, [currentLyricIndex]);
當(dāng) currentLyricIndex
發(fā)生變化時(shí),useEffect
會(huì)被觸發(fā)。在該效果中,它模擬異步加載歌詞,然后通過 scrollRef.current.scrollToElement
方法滾動(dòng)到指定的歌詞元素,滾動(dòng)時(shí)間為500毫秒。這樣,每次歌詞發(fā)生變化時(shí)都會(huì)滾動(dòng)到當(dāng)前高亮的歌詞位置。
Scroll 組件的 scrollToElement 方法實(shí)現(xiàn):
scrollToElement(selector, time = 0) { if (bScroll) { const targetElement = document.querySelector(selector); if (targetElement) { const containerHeight = scrollContainerRef.current.clientHeight; const targetHeight = targetElement.clientHeight; const offsetTop = (containerHeight - targetHeight) / 2; bScroll.scrollToElement(targetElement, time, 0, -offsetTop); } } }
這是 Scroll 組件內(nèi)部的 scrollToElement
方法的實(shí)現(xiàn)。首先,通過 document.querySelector(selector)
獲取到目標(biāo)元素(具有指定類名的高亮歌詞元素)。然后,計(jì)算目標(biāo)元素相對(duì)于滾動(dòng)容器的偏移,最后使用 bScroll.scrollToElement
將目標(biāo)元素滾動(dòng)到可視區(qū)域,傳入的參數(shù)包括時(shí)間、水平和垂直的偏移。
以上就是React實(shí)現(xiàn)歌詞滾動(dòng)效果(跟隨音樂播放時(shí)間滾動(dòng))的詳細(xì)內(nèi)容,更多關(guān)于React歌詞滾動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React實(shí)現(xiàn)錨點(diǎn)跳轉(zhuǎn)組件附帶吸頂效果的示例代碼
這篇文章主要為大家詳細(xì)介紹了React如何實(shí)現(xiàn)移動(dòng)端錨點(diǎn)跳轉(zhuǎn)組件附帶吸頂效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-01-01react-native組件中NavigatorIOS和ListView結(jié)合使用的方法
這篇文章主要給大家介紹了關(guān)于react-native組件中NavigatorIOS和ListView結(jié)合使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-09-09React報(bào)錯(cuò)之組件不能作為JSX組件使用的解決方法
本文主要介紹了React報(bào)錯(cuò)之組件不能作為JSX組件使用的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07深入理解React Native核心原理(React Native的橋接(Bridge)
這篇文章主要介紹了深入理解React Native核心原理(React Native的橋接(Bridge),本文重點(diǎn)給大家介紹React Native的基礎(chǔ)知識(shí)及實(shí)現(xiàn)原理,需要的朋友可以參考下2021-04-04React中實(shí)現(xiàn)組件通信的幾種方式小結(jié)
在構(gòu)建復(fù)雜的React應(yīng)用時(shí),組件之間的通信是至關(guān)重要的,從簡(jiǎn)單的父子組件通信到跨組件狀態(tài)同步,不同組件之間的通信方式多種多樣,下面我們認(rèn)識(shí)react組件通信的幾種方式,需要的朋友可以參考下2024-04-04