Vue實現播放音頻(自定義樣式)


 

本例子是手機端頁面,該音頻播放是某個音頻點擊后跳轉的頁面,需帶播放音頻的url,若需求不一樣,可以把created中從地址去掉從地址欄讀取url,js代碼邏輯不變,可自行改樣式

示例圖

 

 

 

 
         

 

<template>
    <div class="pageWrap rowJcAc">
        <audio ref="audio" autoplay="autoplay"  @ended.stop="audioEnded" :src="audioData.audio_url" controls @loadedmetadata="loadedmetadata" @timeupdate.stop="updateProgress"></audio>
        <div class="contentBox colAc">
            <!-- 中間音頻圖標 -->
            <img src="../../assets/static/task/music.png" alt="" class="musicImg">
            <div class="nameText">音頻文件</div>
            <div class="progressWrap rowAc">
                <div class="startTime">{{audioData.currentTime}}</div>
                <!-- 進度條區域 -->
                <div class="progressBarBox">
                    <div class="progressBox rowAc" @click="clickProgress" ref="progressBox">
                        <div class="progressBar" :style="{width: 'calc('+percentBar+')'}" ref="progressBar"></div>
                        <!-- <div class="progressBar" :style="{width: progressWidth}"></div> -->
                        <div class="progressCirCle" @click.stop="" @touchmove="progressMove" @touchstart="touchstart"></div>
                    </div>
                </div>
                <!-- 結束時間/時長 -->
                <div class="endTime">{{audioData.duration}}</div>
            </div>
            <!-- 播放暫停按鈕圖標 -->
            <img src="../../assets/static/task/audioStop.svg" v-if="!isPlay" alt="" class="controlImg" @click="playAudio('play')">
            <img src="../../assets/static/task/audioPlay.svg" v-else alt="" class="controlImg" @click="playAudio('stop')">
        </div>
    </div>
</template>
<script>
export default {
    data() {
        return {
            audioData: {"audio_name":"20210112_1056.m4a","audio_url":"",duration: '', currentTime: '00:00'},
            // content: [           // 存放audio的地址信息,一般是接口返回
            //     {"audio_name":"20210112_1056.m4a","audio_url":"http://xuke-oss-test-first.oss-cn-shenzhen.aliyuncs.com/TTWY/TTWYXQ000001/homework/audio/79827f5c-8cde-4ccf-add4-7d47e6e20bf9.aac",duration: 0, currentTime: '00:00'},
            //     {"audio_name":"20210112_1056.m4a","audio_url":"http://xuke-oss-test-first.oss-cn-shenzhen.aliyuncs.com/TTWY/TTWYXQ000001/homework/audio/79827f5c-8cde-4ccf-add4-7d47e6e20bf9.aac",duration: 0, currentTime: '00:00'},
            // ]
            percentBar: '0%', // 進度條百分比
            isPlay: true, // 是否是播放狀態
            progressBoxWidth: 0, 
            progressWidth: '0px',
            touchStartX: 0, // 鼠標移動起始位置
            touchStartBarWidth: 0, // 滑塊開始時的寬度
        }
    },
    created() {
        // 判斷地址欄跳轉過來有無帶音頻url若有賦值
        if(this.$route.params.url) {
            this.$set(this.audioData,'audio_url',this.$route.params.url)
        }
    },
    methods: {
        // 音頻初始化完成獲取秒數
        loadedmetadata(event) {
            this.progressBoxWidth = this.$refs.progressBox.offsetWidth
            console.log('progressBoxWidth:',this.progressBoxWidth)
            console.log('錄音時長:',event.target.duration,event)
            this.$set(this.audioData,'duration',this.transTime(event.target.duration))
            this.$forceUpdate()
        },
        // 音頻播放位置發生改變-進度條播放的事件
        updateProgress() {
            let audio = this.$refs.audio
            // let value = Math.round((Math.floor(audio.currentTime) / Math.floor(audio.duration)) * 100, 0)
            let value = ((Math.floor(audio.currentTime) / Math.floor(audio.duration)) * 100).toFixed(2)
            this.$set(this.audioData,'currentTime',this.transTime(audio.currentTime))
            this.percentBar = `${value}%`
            this.$forceUpdate()
            console.log('音頻進度條改變:',this.percentBar)
            this.progressWidth = Math.round(Math.floor(audio.currentTime) * this.progressBoxWidth / Math.floor(audio.duration))+'px'
        },
        // 播放結束的處理動作
        audioEnded() {
            console.log('播放結束')
            this.isPlay = false
            let audio = this.$refs.audio
            // audio.currentTime = 0
            audio.pause()
        },
        playAudio(type) {
            console.log('type:',type)
            let audio = this.$refs.audio
            if(type == 'play') {
                this.isPlay = true
                audio.play()
            }else {
                this.isPlay = false
                audio.pause()
            }
        },
        // 點擊進度條
        clickProgress(event) {
            this.progressBoxWidth = this.$refs.progressBox.offsetWidth
            console.log('progressBoxWidth:',this.progressBoxWidth)
            console.log('點擊進度條:',event)
            var duration = this.$refs.audio.duration
            var currentTime = Math.floor(event.offsetX * duration / this.progressBoxWidth) 
            this.$refs.audio.currentTime = currentTime
            console.log(currentTime,'---',this.$refs.audio.currentTime)
            // this.$set(this.audioData,'currentTime',this.transTime(currentTime))
            // this.progressWidth = event.offsetX >= this.progressBoxWidth ? event.offsetX+'px' : this.progressBoxWidth+'px'
        },
        // 滑塊移動
        progressMove(event) {
            console.log('滑塊移動:',event)
            var duration = this.$refs.audio.duration
            this.$set(this.audioData,'duration',this.transTime(duration))
            var currentTime = Math.floor((this.touchStartBarWidth+event.touches[0].clientX - this.touchStartX) * duration / this.progressBoxWidth)
            currentTime >= duration ? duration : currentTime
            this.$refs.audio.currentTime = currentTime
            // this.$set(this.audioData,'currentTime',this.transTime(currentTime))
        },
        // 滑塊開始觸摸
        touchstart(event) {
            console.log('滑塊開始觸摸:',event)
            this.touchStartX = event.touches[0].clientX
            this.touchStartBarWidth = this.$refs.progressBar.offsetWidth
        },
        // 將秒數轉化成(分:秒)格式
        transTime(time) {
            let duration = parseInt(time)
            let minute = parseInt(duration / 60).toString().padStart(2, '0')
            let sec = (duration % 60).toString().padStart(2, '0')
            return `${minute}:${sec}`
        },
    }
}
</script>
<style lang="scss" scoped>
.pageWrap {
    width: 100%;
    height: 100%;
}
.contentBox {
    
    width: 100%;
    
    .musicImg {
        margin-top: -0.1rem;
        width: .82rem;
        height: .84rem;
    }
    .nameText {
        color: #333843;
        font-size: .14rem;
        font-weight: 500;
        line-height: .21rem;
        margin-top: .2rem;
    }
    .progressWrap {
        margin-top: .46rem;
        width: 100%;
    }
    .startTime {
        color: #333843;
        font-size: .12rem;
        line-height: .18rem;
        margin-left: .18rem;
        margin-right: .16rem;
    }
    .endTime {
        color: #333843;
        font-size: .12rem;
        line-height: .18rem;
        margin-right: .18rem;
        margin-left: .16rem;
    }
    .progressBarBox {
        position: relative;
        flex: 1;
    }
    .progressBox {
        position: relative;
        max-width: 100%;
        // flex: 1;
        // height: .2rem;
        height: 4px;
        border-radius: 2px;
        background: #D8D8D8;
    }
    .progressBar {
        // width: calc(30%);
        max-width: 100% !important;
        height: 4px;
        border-radius: 2px;
        background: #333843;
    }
    .progressCirCle {
        position: relative;
        width: .2rem;
        height: .2rem;
        background: #ffffff;
        border: 1px solid #E6E6E8;
        border-radius: 50%;
        box-sizing: border-box;
        margin-left: -.1rem;
    }
    .controlImg {
        margin-top: .53rem;
        width: .28rem;
        height: .28rem;
    }
}
audio {
    position: absolute;
    top: 0;
    display: block;
    height: 0;
    width: 0;
    opacity: 0;
}
// 橫向排列
.flexRow{
    display: flex;
    flex-direction: row;
}
// 縱向排列
.flexCol{
    display: flex;
    flex-direction: column;
}

// 橫向排列  主軸start 555555555555555555
.rowJs{
    @extend .flexRow;
    justify-content: flex-start;
}
// 橫向排列  主軸between
.rowJb{
    @extend .flexRow;
    justify-content: space-between;
}
// 橫向排列  主軸center
.rowJc{
    @extend .flexRow;
    justify-content: center;
}
// 橫向排列  主軸around
.rowJa{
    @extend .flexRow;
    justify-content: space-around;
}
//  橫向排列  主軸end
.rowJe{
    @extend .flexRow;
    justify-content: flex-end;
}

// 橫向排列  副軸center
.rowAc{
    @extend .flexRow;
    align-items: center;
}
.rowAs{
    @extend .flexRow;
    align-items: flex-start;
}
.rowAe{
    @extend .flexRow;
    align-items: flex-end;
}
// 縱向排列  主軸center
.colJc{
    @extend .flexCol;
    justify-content: center;
}
// 縱向排列  副軸center
.colAc{
    @extend .flexCol;
    align-items: center;
}
// 橫向排列  側軸center  主軸center
.rowJcAc{
    @extend .rowAc;
    justify-content: center;
}
// 橫向排列  副軸center  主軸between
.rowJbAc{
    @extend .rowAc;
    justify-content: space-between;
}
.rowJbAe{
    @extend .rowJb;
    align-items: flex-end;
}
.rowJaAc{
    @extend .rowJa;
    align-items: center;
}
// 縱向排列  主軸center  副軸center
.colJcAc{
    @extend .colJc;
    align-items: center;
}
.colJcAe{
    @extend .colJc;
    align-items: flex-end;
}
// 縱向排列  副軸start
.colAs{
    @extend .flexCol;
    align-items: flex-start;
}
//  橫向排列  副軸center  主軸start
.rowJsAc{
    @extend .rowAc;
    justify-content: flex-start;
}
//   橫向排列  主軸end  副軸center
.rowJeAc{
    @extend .rowJe;
    align-items: center;
}
</style>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM