vue-audio组件,支持拖拽

1 篇文章 0 订阅
1 篇文章 0 订阅

这里写图片描述

<template>
<div style="margin:100px;">
    <!-- 此处的ref属性,可以很方便的在vue组件中通过 this.$refs.audio获取该dom元素 -->
    <audio ref="audio" @pause="onPause" @play="onPlay" @timeupdate="onTimeupdate" @loadedmetadata="onLoadedmetadata" src="http://m10.music.126.net/20180828183443/3609b04d32d19f4799e04ec8b53226ba/ymusic/fbe5/65c6/e2b0/9a32e9c902f057a61150fded0036c8af.mp3"
        controls="controls" style="display:none;"></audio>

    <!-- 音频播放控件 -->
    <div>
        <button @click="startPlayOrPause">{{audio.playing | transPlayPause}}</button>
        <div class="slider" @touchstart="handleTouchStart">
            <div class="slider-track"></div>
            <div class="slider-fill" :style="'width:'+sliderTime+'%'"></div>
            <div class="slider-thumb" :style="'left:'+sliderTime+'%'"></div>
        </div>
        <div>{{ audio.currentTime | formatSecond}}</div>
        <div>{{ audio.maxTime | formatSecond}}</div>
    </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 {
    data() {
        return {
            sliderTime: 0,
            audio: {
                // 该字段是音频是否处于播放状态的属性
                playing: false,
                // 音频当前播放时长
                currentTime: 0,
                // 音频最大播放时长
                maxTime: 0,
                minTime:0,
                step:0.1
            }
        }
    },
    methods: {
        // 控制音频的播放与暂停
        startPlayOrPause() {
            console.log(this.audio.playing)
            return this.audio.playing ? this.pause() : this.play()
        },
        // 播放音频
        play() {
            console.log('你的播放开启了')
            this.$refs.audio.play()
        },
        // 暂停音频
        pause() {
            this.$refs.audio.pause()
        },
        // 当音频播放
        onPlay() {
            console.log('检测到你播放中')
            this.audio.playing = true
        },
        // 当音频暂停
        onPause() {
            this.audio.playing = false
        },
        handleFocus() {
            console.log('focues')
        },
        // 当加载语音流元数据完成后,会触发该事件的回调函数
        // 语音元数据主要是语音的长度之类的数据
        onLoadedmetadata(res) {
            console.log('loadedmetadata')
            // console.log(res)
            this.audio.maxTime = parseInt(res.target.duration)
        },
        // 当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)
        },

        // 进度条格式化toolTip
        formatProcessToolTip(index = 0) {
            index = parseInt(this.audio.maxTime / 100 * index)
            return '进度条: ' + realFormatSecond(index)
        },

        handleTouchStart(e) {
            this.setValue(e.touches[0]);

            document.addEventListener('touchmove', this.handleTouchMove);
            document.addEventListener('touchup', this.handleTouchEnd);
            document.addEventListener('touchend', this.handleTouchEnd);
            document.addEventListener('touchcancel', this.handleTouchEnd);

            // e.preventDefault();
            // this.onDragStart(e);
        },
        handleTouchMove(e){
            console.log(e.changedTouches[0])
            this.setValue(e.changedTouches[0]);
        },
        handleTouchEnd(e) {
            this.setValue(e.changedTouches[0]);
            document.removeEventListener('touchmove', this.handleTouchMove);
            document.removeEventListener('touchup', this.handleTouchEnd);
            document.removeEventListener('touchend', this.handleTouchEnd);
            document.removeEventListener('touchcancel', this.handleTouchEnd);
            // this.onDragStop(e);
        },
        // 从点击位置更新 value
        setValue(e) {
            const $el=this.$el;
            const {
                maxTime,
                minTime,
                step
            } = this.audio;
            let value = (e.clientX - $el.getBoundingClientRect().left) / $el.offsetWidth * (maxTime - minTime);
            value = Math.round(value / step) * step + minTime;
            value = parseFloat(value.toFixed(5));

            if (value > maxTime) {
                value = maxTime;
            } else if (value < minTime) {
                value = minTime;
            }
            this.$refs.audio.currentTime = value;
        },
        // 拖动进度条,改变当前时间,index是进度条改变时的回调函数的参数0-100之间,需要换算成实际时间
        changeCurrentTime(index) {
            console.log('拖动进度条')
            // this.audio.playing && this.pause();
            // console.log('拖动了',index,this.sliderTime,this.audio.maxTime,parseInt(index / 100 * this.audio.maxTime))
            // !this.audio.playing && this.play();
            this.$refs.audio.currentTime = parseInt(index / 100 * this.audio.maxTime)
        }
    },
    filters: {
        // 使用组件过滤器来动态改变按钮的显示
        transPlayPause(value) {
            return value ? '暂停' : '播放'
        },
        // 将整数转化成时分秒
        formatSecond(second = 0) {
            return realFormatSecond(second)
        }
    }
}
</script>

<style lang="less">
.slider {
  margin-top:100px;
    width: 100%;
    position: relative;
    height: 24px;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    cursor: default;
    user-select: none;
    outline: none;
}

.slider-track {
    position: absolute;
    height: 2px;
    left: 0;
    right: 0;
    top: 50%;
    margin-top: -1px;
    background-color: #bec2c1;
}

.slider-fill {
    position: absolute;
    height: 2px;
    width: 100%;
    background-color: #e92e35;
    left: 0;
    top: 50%;
    margin-top: -1px;
}

.slider-thumb {
    position: absolute;
    top: 50%;
    width: 12px;
    height: 12px;
    background-color: #e92e35;
    color: #e92e35;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    cursor: pointer;
}
</style>
  • 7
    点赞
  • 3
    收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 3

打赏作者

张广森

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值