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