本片主要讲解如何使用Vue3去封装一个音频播放器,以及解决在ios微信浏览器中 无法获取音频时长问题
1、安装weixin-js-sdk
cnpm i weixin-js-sdk --save
2、使用,通过wx.ready中重新去加载音频资源
wx.config({
// 可无需配置配置相关参数
debug: false,
appId: '',
timestamp: 1,
nonceStr: '',
signature: '',
jsApiList: []
});
wx.ready(function () {
audioInfo.audioObject.load()
});
1、创建AudioCom.vue文件
<template>
<div class="audio-box">
<div class="action-box">
<div class="actions">
<van-slider
:max="audioInfo.totalTime"
bar-height="3"
button-size="17"
inactive-color="#F0F0F0"
active-color="#ffd55a"
v-model="audioInfo.timeNow"
@change="onChange"
:disabled="!audioInfo.status"
@drag-start="dragState(true)"
@drag-end="dragState(false)"
>
<template #button>
<div class="custom-button" />
</template>
</van-slider>
</div>
<div class="time-row">
<span>{{ getStringTime(audioInfo.timeNow) }}</span>
<span>{{ getStringTime(audioInfo.totalTime) }}</span>
</div>
</div>
<div class="play-control hover" @click="playOrPause" ontouchstart>
<div v-if="!audioInfo.loading">
<van-icon name="play" v-show="!audioInfo.status" />
<van-icon name="pause" v-show="audioInfo.status" />
</div>
<van-loading v-else color="#FF980F"/>
</div>
</div>
</template>
<script lang='ts' setup>
import { audioInit } from './index.hook'
const props = withDefaults(defineProps<{
src?: string,
}>(), {
src: ''
})
const { dragState, getStringTime, playOrPause, onChange, audioInfo } = audioInit(props)
</script>
<style lang="scss" scoped>
.audio-box {
display: flex;
width: 100%;
align-items: center;
margin-left: -10px;
margin-top: 20px;
.play-control {
width: 62px;
height: 62px;
border-radius: 50%;
flex-shrink: 0;
display: flex;
align-items: center;
margin-left: 6px;
justify-content: center;
border: 2px solid #FF980F;
>div {
display: flex;
justify-content: center;
align-items: center;
}
i {
font-size: 45px;
color: #FF980F;
}
}
.action-box {
flex: 1;
position: relative;
min-width: 0;
margin-top: 20px;
.time-row {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 24px;
color: #999999;
margin-top: 20px;
box-sizing: border-box;
padding: 0 15px;
}
.actions {
display: flex;
align-items: center;
>span {
font-size: 22px;
color: #838383;
}
:deep(.van-slider) {
flex: 1;
margin: 0 20px;
}
}
}
}
.custom-button {
width: 10px;
height: 26px;
color: #fff;
font-size: 10px;
line-height: 18px;
text-align: center;
background-color: #FF980F;
border-radius: 100px;
}
</style>
2、创建index.hook.ts文件
import { reactive, watch } from 'vue'
import wx from 'weixin-js-sdk'
export const audioInit = (props: { src: string }) => {
wx.config({
// 配置信息, 即使不正确也能使用 wx.ready
debug: false,
appId: '',
timestamp: 1,
nonceStr: '',
signature: '',
jsApiList: []
});
const audioInfo: any = reactive({
audioObject: null,
timeNow: 0,
totalTime: 1.5,
status: false,
isSlide: false,
loading: false
})
const dragState = (bool: boolean) => {
audioInfo.isSlide = bool;
}
const onChange = (value: number) => {
audioInfo.audioObject.currentTime = value;
}
const playOrPause = () => {
if (audioInfo.totalTime === 1.5 || audioInfo.totalTime === '00:00') {
audioInfo.loading = true
return
}
if (audioInfo.status) {
audioInfo.audioObject.pause();
audioInfo.status = false;
} else {
audioInfo.audioObject.play();
audioInfo.status = true;
}
}
const getStringTime = (time: any) => {
if (time === 1.5 || isNaN(time)) {
return "00:00"
}
let minute: number | string = parseInt(time / 60);
if (minute < 10) {
minute = `0${minute}`;
}
let second: number | string = parseInt(time % 60);
if (second < 10) {
second = `0${second}`;
}
return minute + ":" + second;
}
const resetState = () => {
audioInfo.audioObject = null
audioInfo.totalTime = 1.5
audioInfo.timeNow = 0
audioInfo.status = false
audioInfo.isSlide = false
audioInfo.loading = false
}
// 判断是否是ios环境
const is_iOS = () => {
return /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent);
}
const createAudio = () => {
audioInfo.audioObject = new Audio(props.src);
audioInfo.audioObject.addEventListener(is_iOS() ? "loadedmetadata" : "loadeddata", function () {
audioInfo.totalTime = parseInt(audioInfo.audioObject.duration);
audioInfo.loading = false
});
audioInfo.audioObject.addEventListener("timeupdate", function () {
let tempSecond = parseInt(audioInfo.audioObject.currentTime);
if (audioInfo.timeNow != tempSecond && !audioInfo.isSlide) {
audioInfo.timeNow = tempSecond;
}
});
audioInfo.audioObject.addEventListener("ended", function () {
audioInfo.status = false;
audioInfo.timeNow = 0;
});
wx.ready(function () {
audioInfo.audioObject.load()
});
}
watch(() => props.src, (news) => {
resetState()
if (news) {
createAudio()
}
}, {
deep: true,
immediate: true
})
return {
dragState,
getStringTime,
playOrPause,
onChange,
audioInfo
}
}
大功告成