前端Vue播放音频,音频转写内容自动滚动对应高亮显示

播放音频,内容可根据时间来定位滚动位置(使用element-ui时间线组件)定义div高度

<div class="timeline-container"
               ref="timelineContainer">
            <TimeLine :events="events"
                      ref="timeline" />
          </div>
          <audio :key="audioSourceKey"
                 ref="audioPlayer"
                 controls
                 autoplay
                 @play="startAutoScroll"
                 @pause="stopAutoScroll">
            <source :src="audioSource">
          </audio>
</div>



.timeline-container {
  max-height: 430px;
  overflow-y: auto;
  padding-right: 10px;
}

evens是json类型

color: "#3d9ffe"
content: "喂,你好。"
icon: "el-icon-user-solid"
size: "large"
timeSec: 7
timestamp: "【用户 1】 00:00:07"

timeSec为录音开始时间,等下以此为基准与播放关联

播放启动时调用startAutoScroll方法

startAutoScroll(){
    if (this.scrollAnimation) return; // 防止多次调用
      const audio = this.$refs.audioPlayer;
      const timelineContainer = this.$refs.timelineContainer;
        //获取每个元素
      const timelineItems = this.$refs.timeline.$el.querySelectorAll(".el-timeline-item");
const animateScroll = () => {
        if (!audio || audio.paused) return; // 如果音频暂停,则停止动画

        const currentTime = Math.floor(audio.currentTime); // 取整,防止小数误差

        // 1️、**找到录音中时间戳<=当前时间戳的最大值**
        let validEvents = this.events.filter(event => event.timeSec <= currentTime);  // 找到所有时间戳小于等于当前时间的对象
        let maxTimeSec = Math.max(...validEvents.map(event => event.timeSec)); // 取最大值

        // 2️、**获取所有与最大时间戳相等匹配的索引**(可获取到时间相同获取多个)
        let indices = this.events
          .map((event, index) => (event.timeSec === maxTimeSec ? index : -1))
          .filter(index => index !== -1);

        // 3、**先移除所有高亮**
        timelineItems.forEach(item => item.classList.remove('highlight'));

        // 4、**高亮所有匹配的事件**
        indices.forEach(index => {
          if (timelineItems[index]) {
            timelineItems[index].classList.add('highlight');
          }
        });

        // 5、**滚动匹配元素设置滚动高度**
        const lastIndex = indices[0]; 
        if (timelineItems[lastIndex]) {
          timelineContainer.scrollTo({
            top: timelineItems[lastIndex].offsetTop - (timelineContainer.clientHeight / 2) + (timelineItems[lastIndex].offsetHeight / 2),
            behavior: "smooth",
          });
        }
        this.scrollAnimation = requestAnimationFrame(animateScroll); // 继续下一帧
      };
      this.scrollAnimation = requestAnimationFrame(animateScroll);
    },

// 停止滚动
    stopAutoScroll () {
      const timelineItems = this.$refs.timeline.$el.querySelectorAll(".el-timeline-item");
      if (this.scrollAnimation) {
        cancelAnimationFrame(this.scrollAnimation);
        this.scrollAnimation = null;
        //停止移除高亮
        timelineItems.forEach(item => item.classList.remove('highlight'));
      }
    },

 效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值