在audio标签中存在如下属性:
autoplay:是否音频在就绪后马上播放。
controls:是否向用户显示控件,比如播放按钮。
loop:是否音频结束时重新开始播放。
preload:是否音频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。
src:要播放的音频的 URL。
HTML5 audio支持的音频格式有wav,mp3和ogg格式。
ogg:一种新的音频压缩格式,是完全免费、开放和没有专利限制的。
mp3:是一种音频压缩技术。它被设计用来大幅度地降低音频数据量。
wav:为微软公司开发的一种声音文件格式,声音文件质量和CD相差无几。
以下为组件代码:
//VueAudio.vue
<template>
<div class="di main-wrap" v-loading="audio.waiting">
<!-- 这里设置了ref属性后,在vue组件中,就可以用this.$refs.audio来访问该dom元素 -->
<audio ref="audio" class="dn"
:src="url" :preload="audio.preload"
@play="onPlay"
@error="onError"
@waiting="onWaiting"
@pause="onPause"
@timeupdate="onTimeupdate"
@loadedmetadata="onLoadedmetadata"
></audio>
<div>
//音量条
<div class="volume" v-show="volumeShow">
<el-slider v-show="!controlList.noVolume" v-model="volume" @change="changeVolume" class="sliderMute" vertical height="80px"></el-slider>
</div>
//播放显示
<div class="progress">
<el-tag type="info">{{ audio.currentTime | formatSecond}}</el-tag>
<div class="progressBar">
<el-slider v-show="!controlList.noProcess" v-model="sliderTime" :format-tooltip="formatProcessToolTip" @change="changeCurrentTime" class="slider" ></el-slider>
</div>
<el-tag type="info">{{ audio.maxTime | formatSecond }}</el-tag>
<div class="mute" @click.stop="onVolume">
<img class="muteImg" src="../../../../assets/image/yl02.png" alt="" v-if="80<=volume">
<img class="muteImg" src="../../../../assets/image/yl04.png" alt="" v-else-if="volume > 40 && volume < 80">
<img class="muteImg" src="../../../../assets/image/yl03.png" alt="" v-else-if="volume > 0 && volume <= 40">
<img class="muteImg" src="../../../../assets/image/yl01.png" alt="" v-else>
</div>
</div>
//静音
<el-button v-show="!controlList.noMuted" type="text" @click="startMutedOrNot">{{audio.muted | transMutedOrNot}}</el-button>
//播放/暂停
<div class="playButton">
<el-button type="theme" @click="startPlayOrPause" size="small">{{audio.playing | transPlayPause}}</el-button>
<el-button v-show="!controlList.noSpeed" type="theme" size="small" @click="changeSpeed">{{audio.speed | transSpeed}}</el-button>
</div>
//下载
<a :href="url" v-show="!controlList.noDownload" target="_blank" class="download" download>下载</a>
</div>
</div>
</template>
<script>
function realFormatSecond(second) {
var secondType = typeof second
if (secondType === 'number' || secondType === 'string') {
second = parseInt(second)
var hours = Math.floor(second / 3600)
second = second - hours * 3600
var mimute = Math.floor(second / 60)
second = second - mimute * 60
return hours + ':' + ('0' + mimute).slice(-2) + ':' + ('0' + second).slice(-2)
} else {
return '0:00:00'
}
}
export default {
props: {
theUrl: {
type: String,
required: true,
},
theSpeeds: {
type: Array,
default () {
return [1, 1.5, 2]
}
},
},
name: 'VueAudio',
data() {
return {
url: this.theUrl || 'http://devtest.qiniudn.com/secret base~.mp3',
audio: {
currentTime: 0,
maxTime: 0,
playing: false,
muted: false,
speed: 1,
waiting: true,
preload: 'auto'
},
sliderTime: 0,
volume: 100,
speeds: this.theSpeeds,
controlList: {
// 不显示下载
noDownload: false,
// 不显示静音
noMuted: false,
// 不显示音量条
noVolume: false,
// 不显示进度条
noProcess: false,
// 只能播放一个
onlyOnePlaying: false,
// 不要快进按钮
noSpeed: false
},
volumeShow: false,
}
},
methods: {
//音量条的显示与隐藏
onVolume(event){
if(this.volumeShow){
this.volumeShow = false
}else{
this.volumeShow = true
}
},
//快进
changeSpeed() {
let index = this.speeds.indexOf(this.audio.speed) + 1
this.audio.speed = this.speeds[index % this.speeds.length]
this.$refs.audio.playbackRate = this.audio.speed
},
//静音
startMutedOrNot() {
this.$refs.audio.muted = !this.$refs.audio.muted
this.audio.muted = this.$refs.audio.muted
},
// 音量条toolTip
formatVolumeToolTip(index) {
return '音量条: ' + index
},
// 进度条toolTip
formatProcessToolTip(index = 0) {
index = parseInt(this.audio.maxTime / 100 * index)
return '进度条: ' + realFormatSecond(index)
},
// 音量改变
changeVolume(index = 0) {
this.$refs.audio.volume = index / 100
this.volume = index
},
// 播放跳转
changeCurrentTime(index) {
this.$refs.audio.currentTime = parseInt(index / 100 * this.audio.maxTime)
},
//播放/暂停
startPlayOrPause() {
return this.audio.playing ? this.pausePlay() : this.startPlay()
},
// 开始播放
startPlay() {
this.$refs.audio.play()
},
// 暂停
pausePlay() {
this.$refs.audio.pause()
},
// 当音频暂停
onPause () {
this.audio.playing = false
},
// 当发生错误, 就出现loading状态
onError () {
this.audio.waiting = true
},
// 当音频开始等待
onWaiting (res) {
console.log(res)
},
// 当音频开始播放
onPlay (res) {
console.log(res)
this.audio.playing = true
this.audio.loading = false
if(!this.controlList.onlyOnePlaying){
return
}
let target = res.target
let audios = document.getElementsByTagName('audio');
[...audios].forEach((item) => {
if(item !== target){
item.pause()
}
})
},
// 当timeupdate事件大概每秒一次,用来更新音频流的当前播放时间
onTimeupdate(res) {
// console.log('timeupdate')
// console.log(res)
this.audio.currentTime = res.target.currentTime
this.sliderTime = parseInt(this.audio.currentTime / this.audio.maxTime * 100)
},
// 当加载语音流元数据完成后,会触发该事件的回调函数
// 语音元数据主要是语音的长度之类的数据
onLoadedmetadata(res) {
console.log('loadedmetadata')
console.log(res)
this.audio.waiting = false
this.audio.maxTime = parseInt(res.target.duration)
}
},
filters: {
formatSecond(second = 0) {
return realFormatSecond(second)
},
transPlayPause(value) {
return value ? '暂停' : '播放'
},
transMutedOrNot(value) {
return value ? '放音' : '静音'
},
transSpeed(value) {
return '快进: x' + value
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.main-wrap{
padding: 10px 15px;
}
.progress{
height: 40px;
width: 400px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
border-radius: 14px;
box-shadow: rgba(0, 0, 0, 0.2) 1px 2px 10px;
}
.volume{
position: absolute;
top: 53px;
left: 445px;
border-radius: 10px;
padding: 5px 0px;
box-shadow: rgba(0, 0, 0, 0.2) 1px 2px 10px;
}
.progressBar{
height: 25px;
width: 160px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.mute{
height: 20px;
width: 20px;
cursor: pointer;
}
.muteImg{
height: 20px;
width: 20px;
}
.slider {
display: inline-block;
width: 150px;
position: relative;
/* top: 14px;
margin-left: 15px; */
}
.sliderMute{
display: inline-block;
position: relative;
}
/deep/ .el-slider__button{
width: 0px !important;
height: 0px !important;
}
.di {
display: inline-block;
}
.download {
color: #409EFF;
margin-left: 15px;
}
.dn{
display: none;
}
.playButton{
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-top: 30px;
}
</style>
在父组件中使用:
<template>
<div>
<div class="custm-form-item" v-for="(item,index) in audioList" :key="index">
<el-button @click="aclick(item.url)">{{item.name}}</el-button>
</div>
<el-dialog title="录音" :visible.sync="audioLoging" width="580px!important" style="margin-top: 130px;" :close-on-click-modal="false" :destroy-on-close="true" :modal="false">
<div style="height: 278px;display: flex;flex-direction: column;align-items: center;justify-content: center;" @click.stop="handleChangeAudioVolume" >
<VueAudio ref="audio" :theUrl="music_path" :theControlList="'onlyOnePlaying'"/>
</div>
</el-dialog>
</div>
</template>
<script>
import VueAudio from './VueAudio.vue'
export default {
data() {
return {
music_path: '',
audioList: [
{
name: '录音1',
url: require('../../../../assets/record/recorder.wav'),
controlList: 'onlyOnePlaying'
},
{
name: '录音2',
url: require('../../../../assets/record/falling-star.mp3'),
controlList: 'onlyOnePlaying'
},
],
audioLoging: false,
}
},
methods: {
handleChangeAudioVolume() {//点击空白关闭音量显示
if (this.$refs.audio) this.$refs.audio.volumeShow = false
},
aclick(src) { //打开弹框
this.audioLoging = true
this.music_path = src
},
}
}
</script>