问题:
由于audio标签原生样式不能满足项目需要,需要自定义样式,项目使用技术为vue3和ant-design,将自定义audio封装为一个组件,可以在其他组件内进行引用,主要进行了以下修改:
- 隐藏原生audio标签
- 通过div实现自定义样式
- 控制div操作audio 对象的属性和方法
原生样式:
修改后样式:
组件封装
<template>
<div>
<audio @timeupdate="updateProgress" controls ref="audioRef" style="display: none">
<source :src="fileurl" />
您的浏览器不支持音频播放
</audio>
<div class="audio-right">
<div class="play-stop-icon" @click="playAudio">
<CaretRightOutlined
v-if="audioStatus !== 'pause'"
class="dialogAudioPlay"
></CaretRightOutlined>
<PauseOutlined v-else class="dialogAudioPlay"></PauseOutlined>
</div>
<div class="progress-bar-bg" id="progressBarBg">
<Slider :tip-formatter="formatter" v-model:value="playTime" @change="sliderChange" />
</div>
<div class="audio-time" style="min-height: 10px">
<span class="audio-length-current" id="audioCurTime">{{ audioStart }}</span
>/
<span class="audio-length-total">{{ duration }}</span>
</div>
</div>
</div>
</template>
<script lang="ts">
import {
defineComponent,
ref,
reactive,
watchEffect,
inject,
onMounted,
nextTick,
watch,
computed,
toRef,
toRefs,
} from 'vue';
import { CaretRightOutlined, PauseOutlined } from '@ant-design/icons-vue';
import { propTypes } from '/@/utils/propTypes';
import { Slider } from 'ant-design-vue';
import { transTime } from '/@/utils/time';
export default defineComponent({
components: {
CaretRightOutlined,
PauseOutlined,
Slider,
// [Slider.name]: Slider,
},
props: {
fileurl: propTypes.string,
},
setup(props, context) {
let audioStatus = ref('play');
let audioStart = ref<number | string>('0:00');
let audioVolume = ref(0.5);
let audioHuds = ref(false);
let audioRef = ref<HTMLAudioElement | null>(null);
let duration = ref<number | string>();
let durationSecond = ref<number>();
let playPercentage = ref<number>();
let playTime = ref<number | string>('0:00');
function fetch() {
let myVid = audioRef.value;
if (!myVid) return;
myVid.loop = false;
// 监听音频播放完毕
myVid.addEventListener(
'ended',
function () {
audioStatus.value = 'play'; // 显示播放icon
},
false,
);
if (myVid != null) {
myVid.oncanplay = function () {
durationSecond.value = myVid?.duration;
duration.value = transTime(myVid?.duration); // 计算音频时长
};
myVid.volume = 0.5; // 设置音量50%
}
}
// 播放暂停控制
function playAudio() {
let recordAudio = audioRef.value; // 获取audio元素
if (recordAudio?.paused) {
recordAudio?.play();
audioStatus.value = 'pause';
} else {
recordAudio?.pause();
audioStatus.value = 'play';
}
}
const formatter = (value: number) => {
playTime.value = value;
return audioStart.value;
};
// 更新进度条与当前播放时间
function updateProgress(e) {
playPercentage.value = e.target.currentTime / e.target.duration;
audioStart.value = transTime(e.target.currentTime);
playTime.value = Math.round(Number(playPercentage.value * 100));
if (e.target.currentTime === e.target.duration) {
audioStatus.value = 'pause';
}
}
function sliderChange() {
if (durationSecond.value) {
//拖拽时改变时长
//value 拖拽条的值, durationSecond.value 音频时长的秒数
//value = 当前时间/总时间*100 即 当前时间 = value*总时间/100
audioRef.value!.currentTime = (Number(playTime.value) * durationSecond.value) / 100;
}
}
computed(() => {});
onMounted(() => {
fetch();
});
return {
audioStatus,
audioStart,
duration,
audioVolume,
audioHuds,
audioRef,
fetch,
playAudio,
updateProgress,
playTime,
formatter,
playPercentage,
durationSecond,
sliderChange,
};
},
});
</script>
<style lang="less" scoped>
.audio-right {
width: 100%;
height: 38px;
line-height: 38px;
background: rgba(0, 0, 0, 0.04);
border-radius: 19px;
display: flex;
padding: 0 8px 0 6px;
.play-stop-icon {
background-color: #fff;
height: 30px;
width: 30px;
border-radius: 30px;
margin-top: 4px;
position: relative;
.dialogAudioPlay {
cursor: pointer;
color: #5c5e66;
font-size: 20px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.progress-bar-bg {
flex: 1;
padding-top: 3px;
cursor: pointer;
margin: 0 10px;
}
:global(.ant-slider) {
// height: 100%;
box-sizing: border-box;
}
:global(.ant-slider-rail) {
background-color: #d9d9d9 !important;
}
.progress-bar {
background-color: #56bf8b;
width: 0%;
height: 10px;
border-radius: 5px;
}
.audio-time {
overflow: hidden;
font-size: 14px;
.audio-length-total {
float: right;
}
.audio-length-current {
float: left;
}
}
}
</style>
参考:vue自定义音频audio样式及操作面板https(博主使用的vue2,我根据博主代码改为了vue3,供参考)