首页 > 其他分享 >歌词跟随播放进度高亮显示,高亮部分一直在页面中间位置,歌词可拖动

歌词跟随播放进度高亮显示,高亮部分一直在页面中间位置,歌词可拖动

时间:2024-03-29 14:24:36浏览次数:21  
标签:const lyrics 拖动 歌词 return lyric 高亮 parsedLyrics

//歌词组件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

相关文章

  • 一个vue3指令,兼容pc与移动端的拖动tab切换,鼠标拖动与触摸拖动触控监听
    <Viewclass="app-tabs-container":class="{appear:state.showTabsTrans}"v-tabs-pointer-event:[state.hasMove]="handleProductChange"><router-viewv-slot="{Component}"><KeepAlive>......
  • 【置顶】世末歌者歌词
    给自己唱歌的时候用。蝉时雨化成淡墨渲染暮色渗透着勾勒出足迹与车辙欢笑声与漂浮的水汽饱和隔着窗同城市一并模糊了拨弄着旧吉他哼着四拍子的歌回音中一个人仿佛颇悠然自得等凉雨的温度将不安燥热中和寻觅着风的波折我仍然在无人问津的阴雨霉湿之地和着雨......
  • Antd ProTable 设置表格头,可拖动变换列宽度
    ProTable表格本身是不支持,列宽度可拖动的。1、按照一个插件( react-resizable)npm install --save react-resizable2、新建一个工具类ResizableTableUtil.jsimportReactfrom'react';import{Resizable}from'react-resizable';constResizableTitle=(props)=>......
  • Lyricsx让歌词悬浮于最顶层
    欢迎来到我的博客,代码的世界里,每一行都是一个故事Lyricsx让歌词悬浮于最顶层前言Lyricsx的特色功能:歌词展现的新高度安装在macOS上安装Lyricsx:前言在音符的世界里,歌词是一把打开心扉的钥匙,而Lyricsx就像是这把神奇的钥匙的守护者,让音符更有故事,更有意......
  • Python 查找PDF中的指定文本并高亮显示
    在处理大量PDF文档时,有时我们需要快速找到特定的文本信息。本文将提供以下三个Python示例来帮助你在PDF文件中快速查找并高亮指定的文本。查找并高亮PDF中所有的指定文本查找并高亮PDF某个区域内的指定文本使用正则表达式搜索指定文本并高亮 本文将用到国产第三方库-Spi......
  • vueusejs实现拖动
    https://www.vueusejs.com/guide/ npmi-D@vueuse/nuxt@vueuse/corepnpmadd-D@vueuse/nuxt@vueuse/core定义变量constcontentParent=ref();定义div<divclass="lg:flexoverflow-autoh-6/6w-[calc(100%+1rem)]"ref=&quo......
  • Unity 高亮设置
    highlighter=gameObject.AddComponent<Highlighter>();//highlighter.ConstantOn(Color.red,3f);//红色高亮3秒到最亮highlighter.tweenDuration=1;highlighter.tweenRepeatCount=-1;//闪烁次数highlighter.tween=true;......
  • vue3 监听鼠标点击拖动事件,移动端滑动事件,页面指针坐标事件
    PointerEventsAPI是Hmtl5的事件规范之一,它主要目的是用来将鼠标(Mouse)、触摸(touch)和触控笔(pen)三种事件整合为统一的API。Pointer指可以在屏幕上反馈一个指定坐标的输入设备。PointerEvent事件和TouchEventAPI对应的触摸事件类似,它继承扩展了TouchEvent,因此拥有TouchEven......
  • 解决Puppeteersharp 被检测到的方法, 顺带学习了js如何实现 模拟点击拖动事件
    varlaunchOptions=newLaunchOptions{Headless=false,DefaultViewport=null,IgnoreHTTPSErrors=true,ExecutablePath=path+"\\.local-chromium\\chrome-win\\chr......
  • 旋转拖动验证码解决方案
    前因曾几何时,你是否被一个旋转验证码而困扰,没错今日主题——旋转验证码。 之前也是被他伤透了心,研究了好几天的js,想直接通过接口传输直接解决验证码的,然而我失败了,不过这一次,他来了他来了,他带着RotNet走来了。彩虹屁RotNet也是我无意间发现的,没错时隔了好几个月,他自己出现在......