欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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)歌詞的滾動,首先應該給歌詞設(shè)置一個特定大小的盒子里,然后可以使用overflow:hidden;來對溢出的歌詞進行隱藏。

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

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

記住要給video標簽的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ù)進行處理好后導出給組件使用

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)
//導出
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標簽上對其active類名進行動態(tài)顯示就行了。

第二個問題,偏移量

既然我們之前有給li標簽設(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() {
  //預處理完成,可以開始播放
  console.log('可以開始播放');
}
//處理歌詞點擊事件
const audioChange = (i: any) => {
  audioElement.value.currentTime = i.timestamp + 1;
}
</script>

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

??完整代碼

處理歌詞:

//導出歌詞數(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)
//導出
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)到對應的播放位置。

功能擴展

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

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

相關(guān)文章

  • 深入了解Vue Pinia持久化存儲二次封裝

    深入了解Vue Pinia持久化存儲二次封裝

    Pinia 是2019年由vue.js官方成員重新設(shè)計的新一代狀態(tài)管理庫,類似Vuex,下面我們就來學習一下如何通過Pinia實現(xiàn)持久化存儲的相關(guān)知識,感興趣的小伙伴可以了解下
    2023-12-12
  • vue使用Echarts設(shè)置數(shù)據(jù)無效問題記錄及解決方法

    vue使用Echarts設(shè)置數(shù)據(jù)無效問題記錄及解決方法

    這篇文章主要介紹了vue使用Echarts設(shè)置數(shù)據(jù)無效問題記錄,本文通過場景分析給大家分享解決方法,需要的朋友可以參考下
    2022-08-08
  • vue用復選框?qū)崿F(xiàn)組件且支持單選和多選操作方式

    vue用復選框?qū)崿F(xiàn)組件且支持單選和多選操作方式

    這篇文章主要介紹了vue用復選框?qū)崿F(xiàn)組件且支持單選和多選操作方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • vue樣式穿透 ::v-deep的具體使用

    vue樣式穿透 ::v-deep的具體使用

    這篇文章主要介紹了vue樣式穿透 ::v-deep的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-06-06
  • vue3表單參數(shù)校驗及正則表達式舉例詳解

    vue3表單參數(shù)校驗及正則表達式舉例詳解

    最近項目中有一個校驗身份證號手機號的業(yè)務,索性給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于vue3表單參數(shù)校驗及正則表達式的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-04-04
  • Element中Upload組件上傳功能實現(xiàn)(圖片和文件的默認上傳及自定義上傳)

    Element中Upload組件上傳功能實現(xiàn)(圖片和文件的默認上傳及自定義上傳)

    這篇文章主要介紹了Element中Upload組件上傳功能實現(xiàn)包括圖片和文件的默認上傳及自定義上傳,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01
  • vue實現(xiàn)廣告欄上下滾動效果

    vue實現(xiàn)廣告欄上下滾動效果

    這篇文章主要介紹了vue實現(xiàn)廣告欄上下滾動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • vue實現(xiàn)自定義樹形組件的示例代碼

    vue實現(xiàn)自定義樹形組件的示例代碼

    這篇文章主要介紹了vue實現(xiàn)自定義樹形組件的示例代碼,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • vue項目發(fā)布有緩存正式環(huán)境不更新的解決方案

    vue項目發(fā)布有緩存正式環(huán)境不更新的解決方案

    vue項目每次發(fā)布新版本后,測試人員都要強制刷新才能更新瀏覽器代碼來驗證bug,下面這篇文章主要給大家介紹了關(guān)于vue項目發(fā)布有緩存正式環(huán)境不更新的解決方案,需要的朋友可以參考下
    2024-03-03
  • vue3基于elementplus 簡單實現(xiàn)表格二次封裝過程

    vue3基于elementplus 簡單實現(xiàn)表格二次封裝過程

    公司渲染表格數(shù)據(jù)時需要將空數(shù)據(jù)顯示‘-’,并且對于每一列數(shù)據(jù)的顯示也有一定的要求,基于這個需求對element-plus簡單進行了二次封裝,這篇文章主要介紹了vue3基于elementplus 簡單實現(xiàn)表格二次封裝過程,需要的朋友可以參考下
    2024-05-05

最新評論