Vue3中实现歌词滚动显示效果

您所在的位置:网站首页 vue加自己的音乐 Vue3中实现歌词滚动显示效果

Vue3中实现歌词滚动显示效果

2024-07-11 17:37| 来源: 网络整理| 查看: 265

目录

🎉前言

 🎉整体布局

🎉处理歌词数据

🎉处理事件

🎉完整代码

🎉总结

🎉前言

在这篇博客中,我将分享如何在 Vue 3 中实现一个简单的歌词滚动效果。我将从歌词数据的处理开始,一步步介绍布局的搭建和事件的实现。

 🎉整体布局

1.实现歌词的滚动,首先应该给歌词设置一个特定大小的盒子里,然后可以使用overflow:hidden;来对溢出的歌词进行隐藏。

2.控制当前该高亮的歌词的样式,我是使用transform:scale(1.2)来控制文字变大的。

3.过度动画,给高亮显示的歌词加上过度动画效果,还有整个歌词区域移动的动画效果,以及黑胶唱片的旋转动画。

记住要给video标签的width和height设置为0,虽然默认情况下不显示,但是还是会影响布局的

播放 歌词 .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; //添加一个动画效果,旋转 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); } } } } } 🎉处理歌词数据

这是歌词数据,我把它放在了一个ts文件中,我们可以在这里对数据进行处理好后导出给组件使用

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 我却得到你安慰的淘汰`

现在这样看着是一整个字符串,因为不好操作,所以我们要把它变成我们想要的形式。

我想要的是这种感觉,解析成一个数组就方便我们渲染以及处理事件。

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

// 定义歌词数据类型 type Lyric = { timestamp: number content: string } //解析歌词数据 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 // 将时间戳转换为秒 const timestamp = parseInt(minutes) * 60 + parseInt(seconds) lyrics.push({ timestamp, content }) } } return lyrics } // 使用解析函数获取歌词数组 const lyricsArray: Lyric[] = parseLyrics(dataStr) //导出 export default lyricsArray

这样子,就得到我们想要的结果了

🎉处理事件

首先我们得思考需要处理哪些事件

1.那句歌词得高亮?

2.偏移量为多少?

那么我们先得记得把歌词渲染上去

{{ item.content }} import lyricsArray from './data.ts'

第一个问题,哪句歌词得高亮

在video的dom元素上我们可以通过 currentTime 来获取它此时的播放时间位置,我们可以监听它的位置变化,然后得到需要显示的歌词的 Index,然后再li标签上对其active类名进行动态显示就行了。

第二个问题,偏移量

既然我们之前有给li标签设置line-height ,那么我们就可以再Index变化的时候一起进行计算出来。

可以再添加一个交互,就是用户点击某句歌词,跳动那个地方去

播放 {{ item.content }} import lyricsArray from './data.ts' import { ref, watch } from 'vue'; const audioElement = ref(null); //dom元素 const currentTime = ref('') //播放位置 const activeIndex = ref(0) //高亮Index const transformStyle = ref('') //偏移量 function timeUpdateHandler() { // 处理播放位置变化事件 console.log('播放位置变化事件'); //获取播放的位置 currentTime.value = audioElement.value.currentTime; } //监听播放的位置变化 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; }

这样点击按钮后就能看到完美的效果了

🎉完整代码

处理歌词:

//导出歌词数据 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 我却得到你安慰的淘汰` // 定义歌词数据类型 type Lyric = { timestamp: number content: string } //解析歌词数据 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 // 将时间戳转换为秒 const timestamp = parseInt(minutes) * 60 + parseInt(seconds) lyrics.push({ timestamp, content }) } } return lyrics } // 使用解析函数获取歌词数组 const lyricsArray: Lyric[] = parseLyrics(dataStr) //导出 export default lyricsArray

组件代码:

播放 {{ item.content }} import lyricsArray from './data.ts' import { ref, watch } from 'vue'; const audioElement = ref(null); const currentTime = ref('') const activeIndex = ref(0) const transformStyle = ref('') console.log(lyricsArray); function timeUpdateHandler() { // 处理播放位置变化事件 console.log('播放位置变化事件'); //获取播放的位置 currentTime.value = audioElement.value.currentTime; } //监听播放的位置变化 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; } .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; //添加一个动画效果,旋转 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; } } } } } 🎉总结

歌词数据处理

首先,我们定义了歌词数据的结构 Lyric,并通过 parseLyrics 函数将歌词字符串解析为该类型的数组。这使得我们能够更方便地处理歌词数据。

组件布局

在布局方面,我们设计了一个简单的页面结构,包括音乐播放器、CD封面和歌词展示区域。通过 ref 获取音频元素的引用,并使用 watch 监听播放位置的变化,实现了歌词的滚动效果。

事件处理

我们处理了两个主要事件:timeupdate(播放位置变化事件)和 canplay(可以开始播放事件)。通过监听播放位置变化,实时更新歌词的高亮位置,并在点击歌词时跳转到对应的播放位置。

功能扩展

我这只是实现了小功能,也不一定是最好的解决方案,大家可以增加更多的功能,让交互变得更加的有趣,便捷。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3