You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 9实现带进度条的音频播放/暂停功能求助

实现Angular 9基础音频播放/暂停与进度条功能

没问题,我帮你基于原生HTML5 Audio API来实现基础的音频播放功能,不用依赖第三方组件,完全适配你现有的HTML结构。下面是一步步的实现方案:


第一步:组件类(.ts文件)核心逻辑

首先在你的组件类中初始化音频实例,管理播放状态、进度、音量等变量:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-audio-player',
  templateUrl: './audio-player.component.html',
  styleUrls: ['./audio-player.component.css']
})
export class AudioPlayerComponent implements OnInit {
  @ViewChild('myProgress') myProgress!: ElementRef<HTMLProgressElement>;
  audioInstance!: HTMLAudioElement;
  isPlaying = false;
  currentTime = 0;
  duration = 0;
  volume = 1;
  volumeIcon = 'ion-md-volume-high';
  song: any; // 假设你的song对象包含audio_url字段

  ngOnInit(): void {
    // 初始化音频实例
    this.audioInstance = new Audio();
    // 监听音频加载完成事件,获取总时长
    this.audioInstance.addEventListener('loadedmetadata', () => {
      this.duration = this.audioInstance.duration;
    });
    // 监听播放进度变化,实时更新当前时间
    this.audioInstance.addEventListener('timeupdate', () => {
      this.currentTime = this.audioInstance.currentTime;
    });
    // 监听缓冲进度变化
    this.audioInstance.addEventListener('progress', () => {
      if (this.audioInstance.buffered.length > 0) {
        const bufferedEnd = this.audioInstance.buffered.end(this.audioInstance.buffered.length - 1);
        this.myProgress.nativeElement.value = bufferedEnd;
        this.myProgress.nativeElement.max = this.duration || 1;
      }
    });
    // 播放结束后重置状态
    this.audioInstance.addEventListener('ended', () => {
      this.isPlaying = false;
    });
  }

  // 播放/暂停切换
  play(song: any): void {
    this.song = song;
    // 如果当前播放的不是这首歌,切换音频源
    if (this.audioInstance.src !== song.audio_url) {
      this.audioInstance.src = song.audio_url;
      this.audioInstance.load();
    }
    if (this.isPlaying) {
      this.audioInstance.pause();
      this.isPlaying = false;
    } else {
      this.audioInstance.play();
      this.isPlaying = true;
    }
  }

  // 格式化时间:秒转分:秒
  formatTime(seconds: number): string {
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  }

  // 拖动进度条跳转播放位置
  seekTo(event: Event): void {
    const target = event.target as HTMLInputElement;
    const seekTime = Number(target.value);
    this.audioInstance.currentTime = seekTime;
  }

  // 调整音量并更新图标
  changeVolumeIcon(event: Event): void {
    const target = event.target as HTMLInputElement;
    this.volume = Number(target.value) / 100;
    this.audioInstance.volume = this.volume;
    // 更新音量图标
    if (this.volume === 0) {
      this.volumeIcon = 'ion-md-volume-off';
    } else if (this.volume < 0.5) {
      this.volumeIcon = 'ion-md-volume-low';
    } else {
      this.volumeIcon = 'ion-md-volume-high';
    }
  }

  // 其他辅助方法(按需实现)
  prevSong(): void {
    // 这里实现上一首逻辑
  }

  nextSong(): void {
    // 这里实现下一首逻辑
  }

  toggleRepeat(): void {
    // 这里实现循环逻辑
  }

  toggleShuffle(): void {
    // 这里实现随机逻辑
  }

  openPlaylist(): void {
    // 你的播放列表打开逻辑
  }
}

第二步:修改HTML模板

把你现有的HTML模板中的amplitude相关属性替换成Angular绑定,关联组件类中定义的变量和方法:

<div id="audioPlayer" [class]="playerClass"> 
  <!-- Begin | Audio Player Progress --> 
  <div id="progress-container"> 
    <input 
      type="range" 
      class="amplitude-song-slider"
      [value]="currentTime"
      [max]="duration || 1"
      (input)="seekTo($event)"
    > 
    <progress 
      class="audio-progress audio-progress--played amplitude-song-played-progress"
      [value]="currentTime"
      [max]="duration || 1"
    ></progress> 
    <progress 
      id="myProgress" 
      class="audio-progress audio-progress--buffered amplitude-buffered-progress" 
      #myProgress
    ></progress> 
  </div> 
  <!-- End | Audio Player Progress --> 

  <!-- Begin | Audio --> 
  <div class="audio"> 
    <div class="song-image">
      <img [src]="song?.cover_art_url" alt="{{song?.name}}">
    </div> 
    <div class="song-info pl-3"> 
      <span class="song-name d-inline-block text-truncate">{{song?.name}}</span> 
      <span class="song-artists d-block text-muted">{{song?.artist}}</span> 
    </div> 
  </div> 
  <!-- End | Audio --> 

  <!-- Begin | Audio Controls --> 
  <div class="audio-controls"> 
    <div class="audio-controls--left d-flex mr-auto"> 
      <button class="btn btn-icon-only amplitude-repeat" (click)="toggleRepeat()">
        <i class="ion-md-sync"></i>
      </button> 
    </div> 
    <div class="audio-controls--main d-flex"> 
      <button class="btn btn-icon-only amplitude-prev" (click)="prevSong()">
        <i class="ion-md-skip-backward"></i>
      </button> 
      <button 
        class="btn btn-air btn-pill btn-default btn-icon-only amplitude-play-pause" 
        (click)="play(song)"
      > 
        <i class="ion-md-play" *ngIf="!isPlaying"></i> 
        <i class="ion-md-pause" *ngIf="isPlaying"></i> 
      </button> 
      <button class="btn btn-icon-only amplitude-next" (click)="nextSong()">
        <i class="ion-md-skip-forward"></i>
      </button> 
    </div> 
    <div class="audio-controls--right d-flex ml-auto"> 
      <button class="btn btn-icon-only amplitude-shuffle amplitude-shuffle-off" (click)="toggleShuffle()">
        <i class="ion-md-shuffle"></i>
      </button> 
    </div> 
  </div> 
  <!-- End | Audio Controls --> 

  <!-- Begin | Audio Info --> 
  <div class="audio-info d-flex align-items-center pr-4"> 
    <span class="mr-4"> 
      {{formatTime(currentTime)}} / {{formatTime(duration)}}
    </span> 
    <div class="audio-volume dropdown"> 
      <button class="btn btn-icon-only" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 
        <i [class]="volumeIcon"></i> 
      </button> 
      <div class="dropdown-menu dropdown-menu-right volume-dropdown-menu"> 
        <input 
          type="range" 
          class="amplitude-volume-slider" 
          [value]="volume * 100" 
          (change)="changeVolumeIcon($event)"
        > 
      </div> 
    </div> 
    <!-- Song options --> 
    <app-song-options [icon]="'la-ellipsis-v'" [song]="song"></app-song-options> 
    <button class="btn btn-icon-only" (click)="openPlaylist()">
      <i class="ion-md-musical-note"></i>
    </button> 
  </div> 
  <!-- End | Audio Info --> 
</div> 
<!-- End | Audio Player -->

关键功能说明

  • 播放/暂停:通过HTMLAudioElement的play()和pause()方法实现,同时切换按钮图标和isPlaying状态。
  • 进度条更新:监听timeupdate事件实时获取当前播放时间,绑定到进度条的value属性;总时长在loadedmetadata事件中获取。
  • 缓冲进度:监听progress事件获取已缓冲的音频长度,更新缓冲进度条。
  • 进度拖拽:拖动range输入框时,通过seekTo方法设置音频的currentTime实现跳转。
  • 音量控制:调整range值时更新音频的volume属性,并根据音量大小切换图标。

这样就完成了基础的音频播放功能,完全基于Angular和原生API,不需要依赖第三方组件。你可以根据自己的需求进一步扩展上一首、下一首、循环、随机等功能。

内容的提问来源于stack exchange,提问作者Alexis Lapeze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:57:32