Technology stack used (Vue3.0 +typeScript+Element Plus)

Packaging as components is recommended for use in existing projects. Vue2. X can be modified to not support TS, you can remove the related type judgment, you need different styles, you can define your own styles

H5 Audio Related events and attributes

    <audio
        ref="audio"
        class="audioStyle"
        :src="url"
        :preload="audioState.preload"
        @play="onPlay"
        @error="onError"
        @waiting="onWaiting"
        @pause="onPause"
        @timeupdate="onTimeupdate"
        @loadedmetadata="onLoadedmetadata"
    >
    </audio>
Copy the code
1.SRC is the address of the audio2.The preload attribute specifies whether audio is loaded after the page is loaded - Auto loads the entire audio after the page is loaded - Meta loads only metadata after the page is loaded - None loads no audio after the page is loaded3.OnPlay Play method4.OnPause Pause method5.OnTimeupdate The progress bar can also be updated when the timeUpdate event is used to update the current playback time of the audio stream approximately once per second6.Loadedmetadata Duration for loading audio filesCopy the code

Define the styles and methods used to play recordings

1.OnLoadedmetadata is used to load the audioconst onLoadedmetadata = (res) = > {
    state.audioState.waiting = false
    state.audioState.maxTime = parseInt(res.target.duration)
}
2.Click the pause or play button to invoke audio's corresponding functionconst audio = ref(); // Vue3. X is not written here
const startPlayOrPause=() = > {
    return state.audioState.playing ? pausePlay() : startPlay()
}
// Start playing
const startPlay =() = > {
    audio.value.play()
}
/ / pause
const pausePlay = () = > {
    audio.value.pause()
}
3.Drag the progress bar to update the playback time in real time// Play jump
const changeCurrentTime = (index) = > {
    audio.value.currentTime = Math.floor((index) / 100 * state.audioState.maxTime))
}
4.Change the volume// The volume is changed through audio's volume property
const changeVolume = (index = 0) = > {
    audio.value.volume = Number(index) / 100
    state.volume = index
}
5.Downloading recording Filesconst downloadFile=() = >{
    let temurl=state.url.split('. ').slice(-2) [0].split('/').slice(-1) [0]
    var laststr=temurl.lastIndexOf('_');
    var newStr=temurl.substring(0,laststr);
    let itemName=newStr
    download(state.url,itemName)
}
const download =(url, filename) = > {
    url=url+`?The ${Math.random()}`
    getBlob(url, function(blob:any) { saveAs(blob, filename); })}const getBlob=(url:String,cb:any) = > {
    var xhr:any = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';
    xhr.onload = function() {
        if (xhr.status === 200) { cb(xhr.response); }}; xhr.send(); }const saveAs=(blob, filename) = > {
    var link:any = document.createElement('a');
    var body:any = document.querySelector('body');
    link.href = window.URL.createObjectURL(blob);
    link.download = filename;
    // fix Firefox
    link.style.display = 'none';
    body.appendChild(link);
    link.click();
    body.removeChild(link);
    window.URL.revokeObjectURL(link.href);
}
6.Fast forward by modifying audio's playbackRate propertyconst changeSpeed =() = > {
    let index = state.speeds.indexOf(state.audioState.speed) + 1
    state.audioState.speed = state.speeds[index % state.speeds.length]
    audio.value.playbackRate = state.audioState.speed
}
Copy the code

The complete code

<template>
    <div class="audio_player">
        <audio
            ref="audio"
            class="audioStyle"
            :src="url"
            :preload="audioState.preload"
            @play="onPlay"
            @error="onError"
            @waiting="onWaiting"
            @pause="onPause"
            @timeupdate="onTimeupdate"
            @loadedmetadata="onLoadedmetadata"
        >
        </audio>
        <! -- Function configuration menu function off -->
        <div class="playevent">
            <! -- Pause play -->
            <el-image
                class="hoverClass"
                @click="startPlayOrPause"
                style="width: 30px; height: 30px"
                :src="playStatusurlArr[audioState.playing]"
                fit="scale-down"
                >
             </el-image>
             <div class="split_style"></div>
             <! Fast forward can be configured to disable -->
             <el-button 
                v-if="false" 
                type="text" 
                @click="changeSpeed">{{' fast forward: x' + Audiostate.speed}}</el-button>
             <el-button 
                    type="text" 
                    style="color:#909399;">{{ realFormatSecond(audioState.currentTime)}}
             </el-button>
            <div class="content_solid">
                <el-slider
                    class="slider"
                    v-model="sliderTime"
                    :format-tooltip="formatProcessToolTip"
                    @change="changeCurrentTime" >
                </el-slider>
             </div>
            <el-button type="text" style="color:#909399;">
                {{realFormatSecond(audioState.maxTime)}}
            </el-button>
            <div class="split_style"></div>
            <! -- Mute function can be configured function off -->
            <el-button
                v-if="false" type="text" 
                @click="startMutedOrNot">{{audioState.muted ? 'Play' : 'mute '}}</el-button>
            <div class="voice_solid">
                <el-image
                    @click="moreMiniVoice"
                    class="hoverClass"
                    style="width: 30px; height: 30px; margin-right:8px;"
                    :src="playStatusurlArr['sound']"
                    fit="scale-down"
                    >
                </el-image>
                <el-slider
                    class="sliderVoice"
                    v-model="volume"
                    :format-tooltip="formatVolumeToolTip"
                    @change="changeVolume" >
                </el-slider>
                <el-image
                    @click="moreMaxVoice"
                    class="hoverClass"
                    style="width: 30px; height: 30px"
                    :src="playStatusurlArr['moresound']"
                    fit="scale-down"
                >
                </el-image>

            </div>
            <div class="split_style" style="margin-right: 12px;"></div>
            <! - download - >
            <el-image
                class="hoverClass"
                @click="downloadFile"
                style="width: 30px; height: 30px"
                :src="playStatusurlArr['download']"
                fit="scale-down"
            >
            </el-image>
        </div>
    </div>
</template>
<script lang="ts">
import { onMounted, reactive, toRefs, ref } from 'vue';
export default {
    name: 'audioPlayer'.props: {
        theUrl: {
            type: String.required: true,},theSpeeds: {
            type: Array.default () {
                return [1.1.5.2]}},theControlList: {
            type: String.default: ' '}},setup(props:any, ctx:any) {
    const state=reactive({
        url: props.theUrl,
        audioState: {
            currentTime: 0.maxTime: 0.playing: false.muted: false.speed: 1.waiting: true.preload: 'auto'
        },
        sliderTime: 0.volume: 50.speeds: props.theSpeeds,
        /** * Control function data */
        controlList: {
            // You can configure the passed parameter to display the specific function
        },
        // You need to configure your own image effects here
        playStatusurlArr: {false:' '.true:' '.'download':' '.'sound':' '.'moresound':' ',
        }
    })
    setControlList()
    // When the audio starts playing
    const onPlay = (res:any) = > {
        state.audioState.playing = true
        if(! state.controlList.onlyOnePlaying){return
        }
        let target = res.target
        let audios = document.getElementsByTagName('audio');
        [...audios].forEach((item) = > {
            if(item ! == target){ item.pause() } }) }// When an error occurs, the loading state is loaded
    const onError = () = > {
        state.audioState.waiting = true
    }

    // When the audio starts to wait
    const onWaiting = (res:any) = > {
        console.log(res)
    }

    // When audio pauses

    const onPause = () = > {

    state.audioState.playing = false

    }
    // When a timeUpdate event occurs approximately once per second, it is used to update the current playback time of the audio stream
    const onTimeupdate =(res:any) = > {
        state.audioState.currentTime = res.target.currentTime
        state.sliderTime = Math.floor(Number(state.audioState.currentTime) / Number(state.audioState.maxTime) * 100)}const onLoadedmetadata = (res:any) = > {
        state.audioState.waiting = false
        state.audioState.maxTime = parseInt(res.target.duration)
    }

    /** * the following is the button trigger event */

    const audio = ref();
    const startPlayOrPause=() = > {
        return state.audioState.playing ? pausePlay() : startPlay()
    }

    // Start playing
    const startPlay =() = > {
        audio.value.play()
    }
    / / pause
    const pausePlay = () = > {
        audio.value.pause()
    }

    const changeSpeed =() = > {
        let index = state.speeds.indexOf(state.audioState.speed) + 1
        state.audioState.speed = state.speeds[index % state.speeds.length]
        audio.value.playbackRate = state.audioState.speed
    }

    const realFormatSecond=(second:any) = > {
        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'}}// Progress bar toolTip
    const formatProcessToolTip =(index = 0) = > {
        index =Math.floor(Number(state.audioState.maxTime) / 100 * index)
        return 'Progress bar:' + realFormatSecond(index)
    }
    // Play jump
    const changeCurrentTime = (index:any) = > {
        audio.value.currentTime = Math.floor(Number(index) / 100 * Number( state.audioState.maxTime))
    }
    const startMutedOrNot =() = >{ audio.value.muted = ! audio.value.muted audio.value.muted = audio.value.muted }// Volume bar toolTip
    const formatVolumeToolTip=(index:any) = > {
        return 'Volume bar:' + index
    }
    // The volume changes
    const changeVolume = (index:any = 0) = > {
        audio.value.volume = Number(index) / 100
        state.volume = index
    }
    const moreMiniVoice =() = >{
        audio.value.volume = 0
        state.volume = 0
    }
    const moreMaxVoice =() = >{
        audio.value.volume = 1
        state.volume = 100
    }
    // Download the file
    const downloadFile=() = >{
        let temurl=state.url.split('. ').slice(-2) [0].split('/').slice(-1) [0]
        var laststr=temurl.lastIndexOf('_');
        var newStr=temurl.substring(0,laststr);
        let itemName=newStr
        download(state.url,itemName)
    }
    const download =(url:any, filename:String) = > {
        url=url+`?The ${Math.random()}`
        getBlob(url, function(blob:any) { saveAs(blob, filename); })}const getBlob=(url:String,cb:any) = > {
        var xhr:any = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'blob';
        xhr.onload = function() {
            if (xhr.status === 200) { cb(xhr.response); }}; xhr.send(); }const saveAs=(blob:any, filename:any) = > {
        var link:any = document.createElement('a');
        var body:any = document.querySelector('body');
        link.href = window.URL.createObjectURL(blob);
        link.download = filename;
        // fix Firefox
        link.style.display = 'none';
        body.appendChild(link);
        link.click();
        body.removeChild(link);
        window.URL.revokeObjectURL(link.href);
    }
    onMounted(() = > {
        // Automatically play when clicked
        // startPlayOrPause()
    })
    return {
        ...toRefs(state),
        onPlay,
        onError,
        onWaiting,
        onPause,
        onTimeupdate,
        onLoadedmetadata,
        startPlayOrPause,
        audio,
        changeSpeed,
        realFormatSecond,
        formatProcessToolTip,
        changeCurrentTime,
        startMutedOrNot,
        formatVolumeToolTip,
        changeVolume,
        setControlList,
        downloadFile,
        download,
        getBlob,
        saveAs,
        moreMiniVoice,
        moreMaxVoice,
    }
 }
}

</script>
<style scope>
.audio_player {
    display: inline-block;
    padding:4px 16px 4px 16px;
    border-radius: 4px;
}
.audioStyle {
    display: none;
}
.slider {
    display: inline-block;
    width: 190px;
    margin: 0 15px ;
    margin-top: 4px;
}
.sliderVoice {
    display: inline-block;
    width: 100px;
    margin-right:16px;
}
.download {
    color: #409EFF;
    margin-left: 15px;
}
.playevent {
    display: flex;
    align-items: center;
    justify-content: center;
}
.split_style {
    border-left:1px solid #DCDFE6;
    height:38px;
    margin:0 16px;
    width: 1px;
}
.hoverClass:hover {
    cursor: pointer;
}
</style>
<style>
.audio_player .el-button {
    display: inline-block;
    line-height: 1;
    min-height: 24px;
    padding:0;
}
.audio_player .el-dialog__header {
    padding: 0;
    border-bottom:none;
}
.content_solid .el-slider__button {
    display: inline-block;
    width: 10px;
    height: 10px;
    vertical-align: middle;
    border: 1px solid #025BAC;
    border-radius: 50%;
    box-sizing: border-box;
    box-shadow: 0px 0px 6px 0px rgba(0.0.0.0.3);
    transition:.1s;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background:#025BAC;
}
.voice_solid .el-slider__button {
    width: 16px;
    height: 16px;
    background: #FFFFFF;
    border: 1px solid #fff;
    box-shadow: 0px 0px 6px 0px rgba(0.0.0.0.3);
}
.voice_solid {
    display:flex;
    align-items:center;
}
</style>
Copy the code

The above is all the components in the code recommended all copy for testing and modification

Define the components

Using the component

Component and the cords