1.0.5 • Published 2 months ago

@tanzhenxing/zx-audio v1.0.5

Weekly downloads
-
License
ISC
Repository
-
Last release
2 months ago

zx-audio 音频播放组件

介绍

zx-audio 是一个功能强大的uni-app音频播放组件,支持普通音频播放和背景音频播放模式。该组件提供了丰富的配置选项和事件,使音频播放功能的实现变得简单高效。

特性

  • 支持普通音频播放和背景音频播放
  • 提供完善的音频控制API
  • 自动处理音频状态和生命周期
  • 支持音频加载状态监听
  • 支持播放进度控制
  • 支持音量和播放速率调节
  • 错误处理机制完善

安装和引入

在项目中引入组件

将组件复制到您的项目组件目录下,然后在需要使用的页面中引入:

<script setup>
import ZxAudio from '@/components/zx-audio/zx-audio.vue';
</script>

<template>
  <ZxAudio ref="audioRef" :src="audioSrc" />
</template>

属性说明

属性名类型默认值说明
srcString''音频资源地址
startTimeNumber0开始播放的位置(单位:秒)
autoplayBooleanfalse是否自动播放
loopBooleanfalse是否循环播放
obeyMuteSwitchBooleantrue是否遵循系统静音开关
volumeNumber0.8音量,范围0-1
sessionCategoryString'playback'音频会话类别,可选值:'ambient'、'soloAmbient'、'playback'
playbackRateNumber1.0播放速率,范围0.5-2.0
titleString''音频标题,在背景音频模式下使用
coverImgUrlString''封面图片URL,在背景音频模式下使用
singerString''歌手名称,在背景音频模式下使用
useBackgroundAudioBooleanfalse是否使用背景音频播放模式(允许后台播放)

sessionCategory 说明

  • ambient: 不中止其他声音播放,不能后台播放,静音后无声音
  • soloAmbient: 中止其他声音播放,不能后台播放,静音后无声音
  • playback: 中止其他声音,可以后台播放,静音后有声音

事件说明

事件名说明返回值
onCanplay音频可以播放时触发duration (音频时长)
onPlay音频开始/继续播放时触发-
onPause音频暂停时触发-
onStop音频停止时触发-
onEnded音频自然播放结束时触发-
onTimeUpdate播放进度变化时触发{ duration, currentTime, progress }
onError播放错误时触发error对象
onWaiting音频加载中时触发-
onSeeking音频跳转中时触发-
onSeeked音频跳转完成时触发-
onLoading音频加载状态变化时触发loading状态(Boolean)
onNext背景音频播放下一首时触发(仅背景音频模式)-
onPrev背景音频播放上一首时触发(仅背景音频模式)-

方法说明

通过ref获取组件实例,可以调用以下方法:

方法名说明参数
play开始播放-
pause暂停播放-
stop停止播放-
seek跳转到指定时间time (单位:秒)
destroy销毁音频实例-
change更改音频源并应用设置-
setProgress设置播放进度progress (0-100的数值)
togglePlay切换播放/暂停状态-
getAudioData获取当前音频数据-
setVolume设置音量volume (0-1的数值)
setSrc切换音频源src (音频地址), autoplay (是否自动播放)

使用示例

基本使用

<template>
  <view class="container">
    <zx-audio
      ref="audioRef"
      :src="audioSrc"
      :autoplay="false"
      :loop="false"
      :volume="0.8"
      @onCanplay="onCanplay"
      @onPlay="onPlay"
      @onPause="onPause"
      @onTimeUpdate="onTimeUpdate"
      @onEnded="onEnded"
      @onError="onError"
    />
    
    <view class="controls">
      <button @click="handlePlay">{{ isPaused ? '播放' : '暂停' }}</button>
      <button @click="handleStop">停止</button>
      
      <view class="progress-bar">
        <slider 
          :value="progress" 
          :min="0" 
          :max="100" 
          @change="handleProgressChange" 
        />
        <text>{{ formatTime(currentTime) }} / {{ formatTime(duration) }}</text>
      </view>
      
      <view class="volume-control">
        <text>音量:</text>
        <slider 
          :value="volume * 100" 
          :min="0" 
          :max="100" 
          @change="handleVolumeChange" 
        />
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import ZxAudio from '@/components/zx-audio/zx-audio.vue';

const audioRef = ref(null);
const audioSrc = ref('https://red-education.wufu-app.com/upload/20211123/481d6b654e52961d43c454336a775145.mp3');
const isPaused = ref(true);
const progress = ref(0);
const currentTime = ref(0);
const duration = ref(0);
const volume = ref(0.8);

// 事件处理
const onCanplay = (dur) => {
  duration.value = dur;
  console.log('音频可以播放,时长:', dur);
};

const onPlay = () => {
  isPaused.value = false;
  console.log('音频开始播放');
};

const onPause = () => {
  isPaused.value = true;
  console.log('音频暂停');
};

const onTimeUpdate = (data) => {
  currentTime.value = data.currentTime;
  duration.value = data.duration;
  progress.value = data.progress;
};

const onEnded = () => {
  isPaused.value = true;
  console.log('播放结束');
};

const onError = (err) => {
  console.error('播放错误', err);
};

// 控制方法
const handlePlay = () => {
  if (isPaused.value) {
    audioRef.value.play();
  } else {
    audioRef.value.pause();
  }
};

const handleStop = () => {
  audioRef.value.stop();
  isPaused.value = true;
};

const handleProgressChange = (e) => {
  const value = e.detail.value;
  audioRef.value.setProgress(value);
};

const handleVolumeChange = (e) => {
  const value = e.detail.value / 100;
  volume.value = value;
  audioRef.value.setVolume(value);
};

// 格式化时间
const formatTime = (time) => {
  if (!time) return '00:00';
  const minutes = Math.floor(time / 60);
  const seconds = Math.floor(time % 60);
  return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
};
</script>

背景音频播放示例

<template>
  <view class="container">
    <zx-audio
      ref="bgAudioRef"
      :src="audioInfo.src"
      :title="audioInfo.title"
      :coverImgUrl="audioInfo.coverImgUrl"
      :singer="audioInfo.singer"
      :useBackgroundAudio="true"
      @onPlay="onPlay"
      @onPause="onPause"
      @onTimeUpdate="onTimeUpdate"
      @onEnded="onEnded"
    />
    
    <view class="music-player">
      <image :src="audioInfo.coverImgUrl" class="cover-image" />
      <view class="info">
        <text class="title">{{ audioInfo.title }}</text>
        <text class="singer">{{ audioInfo.singer }}</text>
      </view>
      
      <view class="progress-bar">
        <text>{{ formatTime(currentTime) }}</text>
        <slider 
          :value="progress" 
          :min="0" 
          :max="100" 
          @change="handleProgressChange" 
        />
        <text>{{ formatTime(duration) }}</text>
      </view>
      
      <view class="controls">
        <button @click="playPrev">上一首</button>
        <button @click="handlePlay" class="play-btn">
          {{ isPaused ? '播放' : '暂停' }}
        </button>
        <button @click="playNext">下一首</button>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import ZxAudio from '@/components/zx-audio/zx-audio.vue';

const bgAudioRef = ref(null);
const isPaused = ref(true);
const progress = ref(0);
const currentTime = ref(0);
const duration = ref(0);
const currentIndex = ref(0);

// 播放列表
const playlist = [
  {
    src: 'https://red-education.wufu-app.com/upload/20211123/481d6b654e52961d43c454336a775145.mp3',
    title: '走进新时代',
    singer: '群星',
    coverImgUrl: 'https://red-education.wufu-app.com/upload/20211123/da546a455fe35fd0c510a332f245e201.png'
  },
  {
    src: 'https://red-education.wufu-app.com/upload/20211123/5abc7bc76fb3958e22e2906d206f7c3a.mp3',
    title: '游击队之歌',
    singer: '群星',
    coverImgUrl: 'https://red-education.wufu-app.com/upload/20211123/0cb8673254484ee7d90cd9598eadd2ac.png'
  },
  {
    src: 'https://red-education.wufu-app.com/upload/20211123/e32d0fcda506700a94e23ec9dff7fee9.mp3',
    title: '咱当兵的人',
    singer: '群星',
    coverImgUrl: 'https://red-education.wufu-app.com/upload/20211123/da546a455fe35fd0c510a332f245e201.png'
  }
];

const audioInfo = reactive(playlist[currentIndex.value]);

// 事件处理
const onPlay = () => {
  isPaused.value = false;
};

const onPause = () => {
  isPaused.value = true;
};

const onTimeUpdate = (data) => {
  currentTime.value = data.currentTime;
  duration.value = data.duration;
  progress.value = data.progress;
};

const onEnded = () => {
  playNext();
};

// 控制方法
const handlePlay = () => {
  if (isPaused.value) {
    bgAudioRef.value.play();
  } else {
    bgAudioRef.value.pause();
  }
};

const handleProgressChange = (e) => {
  const value = e.detail.value;
  bgAudioRef.value.setProgress(value);
};

const playNext = () => {
  currentIndex.value = (currentIndex.value + 1) % playlist.length;
  changeMusic();
};

const playPrev = () => {
  currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length;
  changeMusic();
};

const changeMusic = () => {
  Object.assign(audioInfo, playlist[currentIndex.value]);
  setTimeout(() => {
    bgAudioRef.value.change();
    bgAudioRef.value.play();
  }, 50);
};

// 格式化时间
const formatTime = (time) => {
  if (!time) return '00:00';
  const minutes = Math.floor(time / 60);
  const seconds = Math.floor(time % 60);
  return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
};
</script>

<style>
.music-player {
  padding: 20px;
}
.cover-image {
  width: 200px;
  height: 200px;
  border-radius: 8px;
  margin: 0 auto 20px;
  display: block;
}
.info {
  text-align: center;
  margin-bottom: 20px;
}
.title {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 5px;
}
.singer {
  font-size: 14px;
  color: #666;
}
.progress-bar {
  display: flex;
  align-items: center;
  margin: 20px 0;
}
.progress-bar slider {
  flex: 1;
  margin: 0 10px;
}
.controls {
  display: flex;
  justify-content: space-around;
}
.play-btn {
  width: 100px;
}
</style>

注意事项

  1. 在App平台使用背景音频模式时,需要在 manifest.json 中配置:

    • iOS:在 app-plus -> distribute -> ios 节点下添加 "UIBackgroundModes":["audio"]
    • Android:默认不会在通知栏显示音量控制,需要在插件市场下载相关插件
  2. 在小程序平台使用背景音频模式时,需要在 manifest.json 中对应小程序节点下添加 "requiredBackgroundModes": ["audio"]

  3. 不同平台可能存在部分API差异,请根据实际情况调整使用方式

API参考

1.0.5

2 months ago

1.0.3

5 months ago