//歌词组件LyricsDisplay.vue <template> <div class="lyric-container" ref="lyricsList" :class="{ noLyric: !lyrics.length }"> <div v-for="(line, index) in lyrics" :key="index" ref="lyricLine" :class="{ active: index === currentIndex }"> {{ line.text }} </div> <div class="empty-lyric" v-if="!lyrics.length"> 当前歌曲无歌词 </div> </div> </template> <script> export default { props: { lyrics: { type: Array, required: true }, // 已经解析好的歌词对象数组 currentTime: { type: Number, required: true }, // 当前播放时间(秒) }, computed: { currentIndex () { const currentIndexInRange = this.lyrics.findIndex((item, index) => { if (index < this.lyrics.length - 1) { // 防止数组越界 return item.time <= this.currentTime && this.lyrics[index + 1].time > this.currentTime; } return false; // 如果已经是最后一项,返回false,后续不会再检查 }); // 如果没有找到符合条件的歌词,返回-1或其他默认值 return currentIndexInRange !== -1 ? currentIndexInRange : -1; }, }, watch: { currentIndex (newVal) { this.$nextTick(() => { if (newVal > -1) { // 获取当前歌词项对应的DOM元素 const currentLyricElement = this.$refs.lyricLine[newVal]; // 计算容器高度和当前元素高度 const containerHeight = this.$refs.lyricsList.clientHeight; const elementHeight = currentLyricElement.clientHeight; // 计算需要滚动到的偏移量,使元素位于容器中间 const scrollTop = currentLyricElement.offsetTop - this.$refs.lyricsList.offsetTop - (containerHeight / 2 - elementHeight / 2); // 平滑滚动到计算出的偏移量 this.$refs.lyricsList.scrollTop = scrollTop; } }); }, }, }; </script> <style lang="scss" scoped> .lyric-container { overflow-y: scroll; width: 80%; height: 230px; margin: 0 auto; color: rgba(255, 255, 255, 0.3); font-size: 14px; line-height: 34px; text-align: center; .empty-lyric { font-size: 16px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } } .noLyric { position: relative; } .lyric-container::-webkit-scrollbar { display: none; } .active { color: #ffffff; font-size: 16px; } </style>
//解析lrc歌词lyric-parser.js export function parseLyric(lrcContent) { return lrcContent.split('\n').reduce((lyrics, line) => { const timeMatch = /\[(\d{2}:\d{2}(\.\d{2,3})?)\]/.exec(line); if (timeMatch) { const timeStr = timeMatch[1]; const parts = timeStr.split(':').map(parseFloat); const time = parts[0] * 60 + (parts[1] + (parts[2] || 0) / 1000); const lyric = line.replace(timeMatch[0], '').trim(); lyrics.push({ time, text: lyric }); } return lyrics; }, []); }
使用: <template> <div> <audio ref="audio" @timeupdate="updateTime"></audio> <lyrics-display :lyrics="parsedLyrics" :currentTime="currentTime"></lyrics-display> </div> </template> <script> import LyricsDisplay from '@/components/LyricsDisplay.vue'; import { parseLyric } from '@/utils/lyric-parser.js'; export default { components: { LyricsDisplay, }, data () { return { currentTime: 0, parsedLyrics: [], }; }, methods: { updateTime (e) { this.currentTime = e.target.currentTime; }, async function fetchAndParseLyric(url) { try { // 异步请求歌词文件 const response = await fetch(url); const lrcContent = await response.text(); // 使用parseLyric函数解析歌词 const parsedLyrics = parseLyric(lrcContent); // 返回解析后的歌词对象数组 return parsedLyrics; } catch (error) { console.error('Failed to fetch or parse lyric:', error); return null; } }, }, mounted(){ // 调用函数解析歌词 this.fetchAndParseLyric('https://axxx.txt') .then(parsedLyrics => { console.log(parsedLyrics); // 处理解析后的歌词数据 this.parsedLyrics=parsedLyrics }); } }
标签:const,lyrics,拖动,歌词,return,lyric,高亮,parsedLyrics From: https://www.cnblogs.com/chicidol/p/18103753