最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3中實現(xiàn)歌詞滾動顯示效果

 更新時間:2024年02月03日 11:33:29   作者:不會寫代碼  
本文分享如何在Vue 3中實現(xiàn)一個簡單的歌詞滾動效果,我將從歌詞數(shù)據(jù)的處理開始,一步步介紹布局的搭建和事件的實現(xiàn),感興趣的朋友跟隨小編一起看看吧

??前言

在這篇博客中,我將分享如何在 Vue 3 中實現(xiàn)一個簡單的歌詞滾動效果。我將從歌詞數(shù)據(jù)的處理開始,一步步介紹布局的搭建和事件的實現(xiàn)。

 ??整體布局

1.實現(xiàn)歌詞的滾動,首先應(yīng)該給歌詞設(shè)置一個特定大小的盒子里,然后可以使用overflow:hidden;來對溢出的歌詞進行隱藏。

2.控制當(dāng)前該高亮的歌詞的樣式,我是使用transform:scale(1.2)來控制文字變大的。

3.過度動畫,給高亮顯示的歌詞加上過度動畫效果,還有整個歌詞區(qū)域移動的動畫效果,以及黑膠唱片的旋轉(zhuǎn)動畫。

記住要給video標(biāo)簽的width和height設(shè)置為0,雖然默認情況下不顯示,但是還是會影響布局的

<template>
  <div class="box">
    <button @click="audioElement.play()" class="btn">播放</button>
    <!-- 音樂播放器 -->
    <video ref="audioElement" class="video" src="./assets/陳奕迅 - 淘汰.ogg" @timeupdate="timeUpdateHandler"
      @canplay="canPlayHandler">
    </video>
    <div class="cd">
      <img src="./assets/CD.jpg" alt="">
      <div class="msg">
        <ul>
          <li>
            歌詞
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<style scoped lang="scss">
.box {
  width: 100%;
  display: flex;
  align-items: center;
  background-color: #0E0A0D;
  flex-direction: column;
  height: 100vh;
  .btn {
    padding: 10px 15px;
    border: none;
    border-radius: 10%;
    margin-top: 20px;
    background-color: #84CCE6;
    border-color: #84CCE6;
    color: #000;
    cursor: pointer;
  }
  .video {
    width: 0;
    height: 0;
  }
  .cd {
    width: 400px;
    img {
      width: 200px;
      height: 200px;
      border-radius: 50%;
      margin: 100px 0 20px 100px;
      //添加一個動畫效果,旋轉(zhuǎn)
      animation: rotate 5s linear infinite;
      @keyframes rotate {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
    }
  }
  .msg {
    width: 100%;
    height: 300px;
    overflow: hidden;
    ul {
      width: 100%;
      display: flex;
      flex-direction: column;
      //居中
      align-items: center;
      margin-top: 150px;
      transition: ease .5s;
      li {
        list-style: none;
        color: white;
        line-height: 30px;
        transition: all .5s;
        cursor: pointer;
        &.active {
          color: greenyellow;
          transform: scale(1.2);
        }
      }
    }
  }
}
</style>

??處理歌詞數(shù)據(jù)

這是歌詞數(shù)據(jù),我把它放在了一個ts文件中,我們可以在這里對數(shù)據(jù)進行處理好后導(dǎo)出給組件使用

const dataStr = `
00:00 淘汰 – 陳奕迅 (Eason Chan)
00:08 詞:周杰倫
00:17 曲:周杰倫
00:26 編曲:C.Y.Kong
00:35 我說了所有的謊
00:39 你全都相信
00:43 簡單的我愛你
00:46 你卻老不信
00:51 你書里的劇情
00:55 我不想上演
00:58 因為我喜歡
01:01 喜劇收尾
01:08 我試過完美放棄
01:12 的確很踏實
01:15 醒來了夢散了
01:19 你我都走散了
01:23 情歌的詞何必押韻
01:27 就算我是K歌之王
01:31 也不見得把
01:33 愛情唱得完美
01:38 只能說我輸了
01:42 也許是你怕了
01:46 我們的回憶沒有皺褶
01:51 你卻用離開燙下句點
01:54 只能說我認了
01:58 你的不安贏得你信任
02:03 我卻得到你安慰的淘汰
02:25 我試過完美放棄
02:29 的確很踏實
02:32 醒來了夢散了
02:36 你我都走散了
02:40 情歌的詞何必押韻
02:44 就算我是K歌之王
02:48 也不見得把
02:50 愛情唱得完美
02:55 只能說我輸了
02:59 也許是你怕了
03:03 我們的回憶沒有皺褶
03:08 你卻用離開燙下句點
03:11 只能說我認了
03:15 你的不安贏得你信任
03:21 我卻得到你安慰的淘汰
03:44 只能說我輸了
03:48 也許是你怕了
03:52 我們的回憶沒有皺褶
03:57 你卻用離開燙下句點
04:00 只能說我認了
04:04 你的不安贏得你信任
04:09 我卻得到你安慰的淘汰`

現(xiàn)在這樣看著是一整個字符串,因為不好操作,所以我們要把它變成我們想要的形式。

我想要的是這種感覺,解析成一個數(shù)組就方便我們渲染以及處理事件。

 所以我們這里就使用一下分割匹配得到我們想要的效果

// 定義歌詞數(shù)據(jù)類型
type Lyric = {
  timestamp: number
  content: string
}
//解析歌詞數(shù)據(jù)
const parseLyrics = (dataStr: string): Lyric[] => {
  const lines = dataStr.split('\n')
  const lyrics: Lyric[] = []
  for (const line of lines) {
    const match = line.match(/(\d{2}):(\d{2}) (.+)/)
    if (match) {
      const [, minutes, seconds, content] = match
      // 將時間戳轉(zhuǎn)換為秒
      const timestamp = parseInt(minutes) * 60 + parseInt(seconds)
      lyrics.push({ timestamp, content })
    }
  }
  return lyrics
}
// 使用解析函數(shù)獲取歌詞數(shù)組
const lyricsArray: Lyric[] = parseLyrics(dataStr)
//導(dǎo)出
export default lyricsArray

這樣子,就得到我們想要的結(jié)果了

??處理事件

首先我們得思考需要處理哪些事件

1.那句歌詞得高亮?

2.偏移量為多少?

那么我們先得記得把歌詞渲染上去

<li v-for="(item, index) in lyricsArray" :key="item.timestamp">{{ item.content }}</li>
<script setup lang="ts">
import lyricsArray from './data.ts'
</script>

第一個問題,哪句歌詞得高亮

在video的dom元素上我們可以通過 currentTime 來獲取它此時的播放時間位置,我們可以監(jiān)聽它的位置變化,然后得到需要顯示的歌詞的 Index,然后再li標(biāo)簽上對其active類名進行動態(tài)顯示就行了。

第二個問題,偏移量

既然我們之前有給li標(biāo)簽設(shè)置line-height ,那么我們就可以再Index變化的時候一起進行計算出來。

可以再添加一個交互,就是用戶點擊某句歌詞,跳動那個地方去

<template>
  <div class="box">
    <button @click="audioElement.play()" class="btn">播放</button>
    <!-- 音樂播放器 -->
    <video ref="audioElement" class="video" src="./assets/陳奕迅 - 淘汰.ogg" @timeupdate="timeUpdateHandler"
      @canplay="canPlayHandler">
    </video>
    <div class="cd">
      <img src="./assets/CD.jpg" alt="">
      <div class="msg">
        <ul :style="transformStyle">
          <li v-for="(item, index) in lyricsArray" :key="item.timestamp" :class="activeIndex === index ? 'active' : ''"
            @click="audioChange(item)">
            {{ item.content }}
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import lyricsArray from './data.ts'
import { ref, watch } from 'vue';
const audioElement = ref<any>(null); //dom元素
const currentTime = ref<string>('') //播放位置
const activeIndex = ref<number>(0)  //高亮Index
const transformStyle = ref<string>('') //偏移量
function timeUpdateHandler() {
  // 處理播放位置變化事件
  console.log('播放位置變化事件');
  //獲取播放的位置
  currentTime.value = audioElement.value.currentTime;
}
//監(jiān)聽播放的位置變化
watch(currentTime, (newVal) => {
  for (let i = 0; i < lyricsArray.length; i++) {
    if (lyricsArray[i].timestamp < +newVal) {
      activeIndex.value = i
      transformStyle.value = `transform: translateY(${-activeIndex.value * 30}px)`
    }
  }
})
function canPlayHandler() {
  //預(yù)處理完成,可以開始播放
  console.log('可以開始播放');
}
//處理歌詞點擊事件
const audioChange = (i: any) => {
  audioElement.value.currentTime = i.timestamp + 1;
}
</script>

這樣點擊按鈕后就能看到完美的效果了

??完整代碼

處理歌詞:

//導(dǎo)出歌詞數(shù)據(jù)
const dataStr = `
00:00 淘汰 – 陳奕迅 (Eason Chan)
00:08 詞:周杰倫
00:17 曲:周杰倫
00:26 編曲:C.Y.Kong
00:35 我說了所有的謊
00:39 你全都相信
00:43 簡單的我愛你
00:46 你卻老不信
00:51 你書里的劇情
00:55 我不想上演
00:58 因為我喜歡
01:01 喜劇收尾
01:08 我試過完美放棄
01:12 的確很踏實
01:15 醒來了夢散了
01:19 你我都走散了
01:23 情歌的詞何必押韻
01:27 就算我是K歌之王
01:31 也不見得把
01:33 愛情唱得完美
01:38 只能說我輸了
01:42 也許是你怕了
01:46 我們的回憶沒有皺褶
01:51 你卻用離開燙下句點
01:54 只能說我認了
01:58 你的不安贏得你信任
02:03 我卻得到你安慰的淘汰
02:25 我試過完美放棄
02:29 的確很踏實
02:32 醒來了夢散了
02:36 你我都走散了
02:40 情歌的詞何必押韻
02:44 就算我是K歌之王
02:48 也不見得把
02:50 愛情唱得完美
02:55 只能說我輸了
02:59 也許是你怕了
03:03 我們的回憶沒有皺褶
03:08 你卻用離開燙下句點
03:11 只能說我認了
03:15 你的不安贏得你信任
03:21 我卻得到你安慰的淘汰
03:44 只能說我輸了
03:48 也許是你怕了
03:52 我們的回憶沒有皺褶
03:57 你卻用離開燙下句點
04:00 只能說我認了
04:04 你的不安贏得你信任
04:09 我卻得到你安慰的淘汰`
// 定義歌詞數(shù)據(jù)類型
type Lyric = {
  timestamp: number
  content: string
}
//解析歌詞數(shù)據(jù)
const parseLyrics = (dataStr: string): Lyric[] => {
  const lines = dataStr.split('\n')
  const lyrics: Lyric[] = []
  for (const line of lines) {
    const match = line.match(/(\d{2}):(\d{2}) (.+)/)
    if (match) {
      const [, minutes, seconds, content] = match
      // 將時間戳轉(zhuǎn)換為秒
      const timestamp = parseInt(minutes) * 60 + parseInt(seconds)
      lyrics.push({ timestamp, content })
    }
  }
  return lyrics
}
// 使用解析函數(shù)獲取歌詞數(shù)組
const lyricsArray: Lyric[] = parseLyrics(dataStr)
//導(dǎo)出
export default lyricsArray

組件代碼:

<template>
  <div class="box">
    <button @click="audioElement.play()" class="btn">播放</button>
    <!-- 音樂播放器 -->
    <video ref="audioElement" class="video" src="./assets/陳奕迅 - 淘汰.ogg" @timeupdate="timeUpdateHandler"
      @canplay="canPlayHandler">
    </video>
    <div class="cd">
      <img src="./assets/CD.jpg" alt="">
      <div class="msg">
        <ul :style="transformStyle">
          <li v-for="(item, index) in lyricsArray" :key="item.timestamp" :class="activeIndex === index ? 'active' : ''"
            @click="audioChange(item)">
            {{ item.content }}
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import lyricsArray from './data.ts'
import { ref, watch } from 'vue';
const audioElement = ref<any>(null);
const currentTime = ref<string>('')
const activeIndex = ref<number>(0)
const transformStyle = ref<string>('')
console.log(lyricsArray);
function timeUpdateHandler() {
  // 處理播放位置變化事件
  console.log('播放位置變化事件');
  //獲取播放的位置
  currentTime.value = audioElement.value.currentTime;
}
//監(jiān)聽播放的位置變化
watch(currentTime, (newVal) => {
  for (let i = 0; i < lyricsArray.length; i++) {
    if (lyricsArray[i].timestamp < +newVal) {
      activeIndex.value = i
      transformStyle.value = `transform: translateY(${-activeIndex.value * 30}px)`
    }
  }
})
function canPlayHandler() {
  // 處理可以開始播放事件
  console.log('可以開始播放事件');
}
//處理歌詞點擊事件
const audioChange = (i: any) => {
  audioElement.value.currentTime = i.timestamp + 1;
}
</script>
<style scoped lang="scss">
.box {
  width: 100%;
  display: flex;
  align-items: center;
  background-color: #0E0A0D;
  flex-direction: column;
  height: 100vh;
  .btn {
    padding: 10px 15px;
    border: none;
    border-radius: 10%;
    margin-top: 20px;
    background-color: #84CCE6;
    border-color: #84CCE6;
    color: #000;
    cursor: pointer;
  }
  .video {
    width: 0;
    height: 0;
  }
  .cd {
    width: 400px;
    img {
      width: 200px;
      height: 200px;
      border-radius: 50%;
      margin: 100px 0 20px 100px;
      //添加一個動畫效果,旋轉(zhuǎn)
      animation: rotate 5s linear infinite;
      @keyframes rotate {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
    }
  }
  .msg {
    width: 100%;
    height: 300px;
    overflow: hidden;
    ul {
      width: 100%;
      display: flex;
      flex-direction: column;
      //居中
      align-items: center;
      margin-top: 150px;
      transition: ease .5s;
      li {
        list-style: none;
        color: white;
        line-height: 30px;
        transition: all .5s;
        cursor: pointer;
        &.active {
          color: greenyellow;
          transform: scale(1.3);
          // font-size: 30px;
        }
      }
    }
  }
}
</style>

??總結(jié)

歌詞數(shù)據(jù)處理

首先,我們定義了歌詞數(shù)據(jù)的結(jié)構(gòu) Lyric,并通過 parseLyrics 函數(shù)將歌詞字符串解析為該類型的數(shù)組。這使得我們能夠更方便地處理歌詞數(shù)據(jù)。

組件布局

在布局方面,我們設(shè)計了一個簡單的頁面結(jié)構(gòu),包括音樂播放器、CD封面和歌詞展示區(qū)域。通過 ref 獲取音頻元素的引用,并使用 watch 監(jiān)聽播放位置的變化,實現(xiàn)了歌詞的滾動效果。

事件處理

我們處理了兩個主要事件:timeupdate(播放位置變化事件)和 canplay(可以開始播放事件)。通過監(jiān)聽播放位置變化,實時更新歌詞的高亮位置,并在點擊歌詞時跳轉(zhuǎn)到對應(yīng)的播放位置。

功能擴展

我這只是實現(xiàn)了小功能,也不一定是最好的解決方案,大家可以增加更多的功能,讓交互變得更加的有趣,便捷。

到此這篇關(guān)于Vue3中實現(xiàn)歌詞滾動顯示效果的文章就介紹到這了,更多相關(guān)Vue3歌詞滾動顯示內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue中Object.assign清空數(shù)據(jù)報錯的解決方案

    Vue中Object.assign清空數(shù)據(jù)報錯的解決方案

    這篇文章主要介紹了Vue中Object.assign清空數(shù)據(jù)報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • vue3+ts項目中.env配置環(huán)境變量與情景配置方式

    vue3+ts項目中.env配置環(huán)境變量與情景配置方式

    本文介紹了如何在Vite中配置環(huán)境變量和不同的運行模式,環(huán)境變量文件以.env開頭,僅VITE_前綴的變量會被暴露,開發(fā)模式加載.env.development,生產(chǎn)模式加載.env.production,NODE_ENV用于區(qū)分開發(fā)和生產(chǎn)環(huán)境
    2024-10-10
  • Vue Swiper組件實現(xiàn)記錄

    Vue Swiper組件實現(xiàn)記錄

    文章講解Vue2中使用Swiper組件的實現(xiàn)步驟,包括版本適配、組件結(jié)構(gòu)搭建、依賴安裝、ESLint配置、數(shù)據(jù)加載與圖片路徑處理,以及響應(yīng)式樣式設(shè)置,確保組件正常運行,感興趣的朋友跟隨小編一起看看吧
    2025-07-07
  • vue封裝組件js版基本步驟

    vue封裝組件js版基本步驟

    這篇文章主要為大家介紹了vue封裝組件js版基本步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-04-04
  • 深入探討Vue3組件中的圖片懶加載的實現(xiàn)原理與應(yīng)用

    深入探討Vue3組件中的圖片懶加載的實現(xiàn)原理與應(yīng)用

    本文將深入探討?Vue3?中圖片懶加載的實現(xiàn)原理,從底層的?IntersectionObserver?到高級的?LQIP?漸進式加載,最終手寫一個完整的圖片懶加載指令和預(yù)加載組件,感興趣的小伙伴可以了解下
    2026-03-03
  • Vue?打包優(yōu)化之externals抽離公共的第三方庫詳解

    Vue?打包優(yōu)化之externals抽離公共的第三方庫詳解

    這篇文章主要為大家介紹了Vue?打包優(yōu)化之externals抽離公共的第三方庫詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2023-06-06
  • vue-router beforeEach跳轉(zhuǎn)路由驗證用戶登錄狀態(tài)

    vue-router beforeEach跳轉(zhuǎn)路由驗證用戶登錄狀態(tài)

    這篇文章主要介紹了vue-router beforeEach跳轉(zhuǎn)路由驗證用戶登錄狀態(tài),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • vue內(nèi)點擊url下載文件的最佳解決方案分享

    vue內(nèi)點擊url下載文件的最佳解決方案分享

    這篇文章主要給大家介紹了關(guān)于vue內(nèi)點擊url下載文件的最佳解決方案,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-02-02
  • vue項目中極驗驗證的使用代碼示例

    vue項目中極驗驗證的使用代碼示例

    這篇文章主要介紹了vue項目中極驗驗證的使用代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • vue src動態(tài)加載請求獲取圖片的方法

    vue src動態(tài)加載請求獲取圖片的方法

    這篇文章主要為大家詳細介紹了vue src動態(tài)加載請求獲取圖片的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10

最新評論

得荣县| 阿克陶县| 博湖县| 长子县| 苏尼特右旗| 灯塔市| 固阳县| 志丹县| 扶绥县| 龙胜| 乐山市| 衡南县| 东辽县| 城步| 封丘县| 朔州市| 马山县| 凤阳县| 梓潼县| 鸡泽县| 营口市| 温宿县| 乌海市| 东丰县| 乃东县| 海伦市| 高安市| 紫金县| 昌吉市| 东平县| 北宁市| 新建县| 新安县| 内黄县| 沁水县| 独山县| 清远市| 额敏县| 桂阳县| 西丰县| 柳河县|