vue3+ts项目封装音频播放与使用

AudioPlayer.vue

<template>
    <!-- 这个组件是一个逻辑组件,不需要渲染任何UI -->
    <span></span>
  </template>
  
  <script lang="ts">
  import { defineComponent, watch, onUnmounted, ref } from 'vue'
  
  export default defineComponent({
    name: 'AudioPlayer',
    props: {
      // 音频源,可以是URL或base64数据
      src: {
        type: String,
        required: true
      },
      // 控制播放状态:'play' 开始播放,'stop' 停止播放
      command: {
        type: String as () => 'play' | 'stop',
        default: 'stop',
        validator: (value: string) => ['play', 'stop'].includes(value)
      },
      // 是否循环播放
      loop: {
        type: Boolean,
        default: false
      },
      // 音量 0-1
      volume: {
        type: Number,
        default: 1,
        validator: (value: number) => value >= 0 && value <= 1
      }
    },
    emits: ['play-start', 'play-end', 'play-error'],
    setup(props, { emit }) {
      const audioRef = ref<HTMLAudioElement | null>(null)
      let audio: HTMLAudioElement | null = null
  
      // 初始化音频
      const initAudio = () => {
        if (audio) {
          destroyAudio()
        }
        audio = new Audio(props.src)
        audio.loop = props.loop
        audio.volume = props.volume
        
        audio.addEventListener('ended', handlePlayEnd)
        audio.addEventListener('error', handlePlayError)
      }
  
      // 销毁音频
      const destroyAudio = () => {
        if (audio) {
          stop()
          audio.removeEventListener('ended', handlePlayEnd)
          audio.removeEventListener('error', handlePlayError)
          audio = null
        }
      }
  
      // 播放音频
      const play = async () => {
        if (!audio) {
          initAudio()
        }
        
        try {
          if (audio) {
            await audio.play()
            emit('play-start')
          }
        } catch (error) {
          emit('play-error', error)
        }
      }
  
      // 停止播放
      const stop = () => {
        if (audio && !audio.paused) {
          audio.pause()
          audio.currentTime = 0
          emit('play-end')
        }
      }
  
      const handlePlayEnd = () => {
        if (!props.loop) {
          emit('play-end')
        }
      }
  
      const handlePlayError = (error: Event) => {
        emit('play-error', error)
      }
  
      // 监听命令变化
      watch(() => props.command, (newCommand) => {
        if (newCommand === 'play') {
          play()
        } else if (newCommand === 'stop') {
          stop()
        }
      })
  
      // 监听src变化
      watch(() => props.src, () => {
        initAudio()
      })
  
      // 监听音量变化
      watch(() => props.volume, (newVolume) => {
        if (audio) {
          audio.volume = newVolume
        }
      })
  
      // 监听循环设置变化
      watch(() => props.loop, (newLoop) => {
        if (audio) {
          audio.loop = newLoop
        }
      })
  
      // 组件卸载时清理
      onUnmounted(() => {
        destroyAudio()
      })
  
      return {
        audioRef
      }
    }
  })
  </script>

使用AudioPlayer.vue
(该组件有个bug时好时坏,详情描述:需播放4个音频文件,点击播放按钮播放完第一个音频后,在音频播放完成方法onPlayEnd中继续写播放第二个音频,其次第三个,依此类推,会出现只播放完第一个音频后其余的几个都不播放,或者播放完前3个第四个不播放的情况,但在控制台打印都正常,所以有了第二个音频组件。q_q)

<template>
<button class='btn' @click='playAudio'>点击播放音频</button>
<AudioPlayer 
            :src="audioSrc" 
            :command="playCommand" 
            @play-start="onPlayStart"
            @play-end="onPlayEnd"
            @play-error="onPlayError"
            v-if="audioSrc"
        />
</temp
late>
<script lang="ts" steup>
import { ref  } from 'vue'
import AudioPlayer from '@/components/AudioPlayer.vue'
import audio1 from '@/assets/audio/1.MP3'

const audioSrc = ref<any>(audio1);
const playCommand = ref<'play' | 'stop'>('stop')

// 开始播放音频
const startPlay = (src : any) => {
    stopPlay();
    audioSrc.value = src;
    setTimeout(() => {
        playCommand.value = 'play'
    }, 100);
}
// 停止播放音频
const stopPlay = () => {
    console.log('停止播放音频')
    playCommand.value = 'stop'
}
// 音频播放开始
const onPlayStart = () => {
    console.log('音频开始播放')
}
// 音频播放结束
const onPlayEnd = () => {
    // console.log('音频播放结束')
    playCommand.value = 'stop'; // 重置状态 
    
}
// 音频播放出错
const onPlayError = (error: Event) => {
    console.error('播放错误:', error)
    playCommand.value = 'stop' // 出错时也重置状态
}


AudioPlayerV2.vue (解决上一个组件连续播放多个音频无声bug)

<template>
    <audio controls ref="audioPlayer"></audio>
</template>
<script lang="ts" setup>
import { ref, defineEmits, defineProps, defineExpose } from 'vue'

//组件参数获取
const props = defineProps({ 
    // 是否显示弹框
    audioList: {
        type: Array,
        default: [] as any[]
    // 当前播放的音频索引
    },
});

const audioPlayer = ref<HTMLAudioElement | null>(null);
let currentIndex = 0;

const playAudioSequence = () => {
  currentIndex = 0
  playNextAudio()
}

const playNextAudio = () => {
  if (!audioPlayer.value || currentIndex >= props.audioList.length) return
  
  // 设置音频源
  audioPlayer.value.src = String(props.audioList[currentIndex]);
  
  // 播放当前音频
  audioPlayer.value.play().catch(error => {
    console.error('播放失败:', error)
  })
  
  // 监听播放结束事件
  audioPlayer.value.onended = () => {
    currentIndex++
    if (currentIndex < props.audioList.length) {
      // 延迟500毫秒播放下一个音频
      setTimeout(playNextAudio, 500)
    }
  }
}

defineExpose({
  playAudioSequence,
})

</script>

使用方法

<template>
<button class='btn' @click='playAudioSequence'>点击播放音频</button>
<AudioPlayerV2 ref="audioPlayer" :audio-list="audioList"/>
</temp
late>
<script lang="ts" steup>
import { ref  } from 'vue'
import AudioPlayerV2 from '@/components/m/AudioPlayerV2.vue';
import audio1 from '@/assets/audio/1.MP3'
import audio2 from '@/assets/audio/2.MP3'
import audio3 from '@/assets/audio/3.MP3'
import audio4 from '@/assets/audio/4.MP3'

const audioPlayer = ref<InstanceType<typeof AudioPlayerV2> | null>(null);
const audioList = ref([audio1, audio2, audio3, audio4]);

const playAudioSequence = () => {
    audioPlayer.value?.playAudioSequence();
}

Vue 3 + TypeScript项目使用lamejs进行音频格式转换,可按以下步骤操作: ### 1. 安装lamejs 首先,在项目中安装lamejs库。在终端中运行以下命令: ```bash npm install lamejs ``` ### 2. 创建转换函数 参考提供的引用,创建一个用于音频格式转换的函数。在Vue 3 + TypeScript项目中,可以将该函数封装在一个组件或一个独立的模块中。以下是一个示例函数: ```typescript import lamejs from &#39;lamejs&#39;; export function changeFormat(recorderData: ArrayBuffer): Blob { const channels = 1; // 1 单声道 2 立体声 const sampleRate = 44100; // 44.1khz const kbps = 128; // 128kbps mp3 const mp3encoder = new lamejs.Mp3Encoder(channels, sampleRate, kbps); const mp3Data: Int8Array[] = []; const samples = new Int16Array(recorderData); // 从源中获取数据 const sampleBlockSize = 1152; // 576的倍数 for (let i = 0; i < samples.length; i += sampleBlockSize) { const sampleChunk = samples.subarray(i, i + sampleBlockSize); const mp3buf = mp3encoder.encodeBuffer(sampleChunk); if (mp3buf.length > 0) { mp3Data.push(new Int8Array(mp3buf)); } } const mp3buf = mp3encoder.flush(); // finish writing mp3 if (mp3buf.length > 0) { mp3Data.push(new Int8Array(mp3buf)); } const blob = new Blob(mp3Data, { type: &#39;audio/mp3&#39; }); return blob; } ``` ### 3.Vue 3组件中使用转换函数 以下是一个简单的Vue 3 + TypeScript组件示例,展示如何使用上述转换函数: ```vue <template> <div> <!-- 可以添加音频录制和上传的UI --> <button @click="convertAudio">转换音频</button> </div> </template> <script lang="ts" setup> import { ref } from &#39;vue&#39;; import { changeFormat } from &#39;./path/to/your/formatConverter&#39;; const audioData = ref<ArrayBuffer | null>(null); const convertAudio = () => { if (audioData.value) { const mp3Blob = changeFormat(audioData.value); // 可以在这里处理转换后的MP3 Blob,例如下载或上传 console.log(&#39;转换后的MP3 Blob:&#39;, mp3Blob); } }; </script> ``` ### 4. 注意事项 - 需要确保 `audioData` 变量包含有效的音频数据的 `ArrayBuffer`。在实际应用中,这可能来自音频录制或文件上传。 - 处理错误和异常情况,例如 `lamejs` 编码失败或 `ArrayBuffer` 无效。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值