自定义实现aduio播放器(vue3)

实现自定义aduio播放器

在项目中有两款样式,有些细节上的区分,但是整体api相似

在这里插入图片描述
在这里插入图片描述
样式不进行细节的讲解和展示。
使用vue3,提取useAduiohooks进行复用。
原理:
利用audio 的回调和属性来进行音频的播放、时间调整等。

  1. canplay:音频加载,可以播放
  2. handleTimeUpdate:更新时间
  3. end:播放结束,更换播放按钮
  4. .play():播放
  5. .pause():暂停
  6. .currentTime:当前时间

template代码:

<template>
    <div class="audio-container j-between flex">
        <div class="flex-1">
        //时间
            <div class="j-between flex">
                <span>{{ currentTime }}</span>
                <span class="mgl-6">{{ duration }}</span>
            </div>
            //播放线条
            <div class="audio-setbacks" ref="setbacksBox" @click="handleBacks">
                <i class="audio-this-setbacks" :style="{ width: progress + '%' }">
                    <span class="audio-backs-btn"></span>
                </i>
                <span class="audio-cache-setbacks" :style="{ width: progress + '%' }">
                </span>
            </div>
        </div>

		//播放按钮
        <img src="@/assets/home/play.png" v-if="!isPlay" class="play-icon mgl-18" @click="handlePlay" />
        <img src="@/assets/home/p.png" v-else class="play-icon mgl-18" @click="handlePlay" />
    </div>

	//不展示的aduio用来获取视频长度等
    <audio ref="aduio" :src="url" style="display: none;" class="custom-audio" @canplay="handleCanPlay"
        @ended="handleEnd" @timeupdate="handleTimeUpdate" controls="controls">
        Your browser does not support the audio element.
    </audio>
</template>

<script setup>
import useAduio from '@/hooks/aduio.js';
import { defineProps } from 'vue';

const props = defineProps({
    url: {
        type: String,
        default: ''
    }
});
const { aduio, setbacksBox, currentTime, progress, duration, isPlay, handlePlay, handleBacks, handleTimeUpdate, handleCanPlay, handleEnd } = useAduio();
</script>

<style>
//有些样式代码没有复制上来,基于工程有些通用性css,可自行调整下样式。
audio,
audio source {
  width: 100%;
  background: #DFFFFA;
  border-radius: 8px 8px 8px 8px;
}

.audio-setbacks {
  height: 2px;
  border-radius: 3px;
  background-color: #CDE1DD;
  cursor: pointer;
  width: 100%;
  position: relative;
  margin-top: 6px;
}



.audio-cache-setbacks,
.audio-this-setbacks {
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  border-radius: 3px;
}

.audio-cache-setbacks {
  width: 0;
  background-color: #FFA358;
  z-index: 1;
  cursor: pointer;
  transition: width 0.3s ease;
  -webkit-transition: width 0.3s ease;
}

.audio-this-setbacks {
  background-color: #FFA358;
}

.audio-backs-btn {
  position: absolute;
  right: -3px;
  margin-top: -2px;
  width: 6px;
  height: 6px;
  background-color: #FFA358;
  border-radius: 50%;
  cursor: pointer;
}

.audio-cache-setbacks,
.audio-this-setbacks {
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  border-radius: 3px;
}
</style>

hooks

import { ref, onMounted } from 'vue';

export default function useAduio() {

    const aduio = ref(null);
    const setbacksBox = ref(null)
    const currentTime = ref(0);
    const progress = ref(0)
    const duration = ref(0);
    const isPlay = ref(false)

    // 初始化
    onMounted(() => {
        setTimeout(() => {
            handleTimeUpdate()
        }, 200);
    })

    /**
     * 能够播放时的回调
     * @param {Event} event 事件对象
     */
    const handleCanPlay = (event) => {
        // 更新当前时间
        handleTimeUpdate()
        // 播放
        handlePlay()
    }


    // 格式化时间
    function formatSeconds(seconds) {
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = seconds % 60;
        const formattedMinutes = String(minutes).padStart(2, '0');
        const formattedSeconds = String(remainingSeconds).padStart(2, '0');
        return `${formattedMinutes}:${formattedSeconds}`;
    }

    // 点击时间
    const handleBacks = (event) => {
        const childRect = setbacksBox.value.getBoundingClientRect();
        const clickX = event.clientX - childRect.left;
        let progressValue = (clickX / childRect.width)
        let value = (progressValue * 100)
        progress.value = value
        let time = progressValue * aduio.value.duration
        currentTime.value = formatSeconds(Math.floor(time));
        aduio.value.currentTime = time
        handlePlay()
    }

    //更新时间
    const handleTimeUpdate = () => {
        let curTime = aduio.value?.currentTime ?? 0
        let durTime = isNaN(aduio.value?.duration ?? 0) ? 0 : aduio.value?.duration ?? 0
        currentTime.value = formatSeconds(Math.floor(curTime));
        duration.value = formatSeconds(Math.floor(durTime));
        progress.value = (Math.floor(curTime) / Math.floor(durTime)) * 100
    };


    /**
     * 播放/暂停
     * @description 如果当前是暂停状态,就播放,否则暂停
     * @param {Event} event 事件对象
     */
    const handlePlay = (event) => {
        if (aduio.value.paused) {
            // 如果当前是暂停状态,就播放
            aduio.value.play().catch(error => {
                console.error(error);
            });
            isPlay.value = true
        } else {
            // 如果当前不是暂停状态,就暂停
            aduio.value.pause();
            isPlay.value = false
        }
    }


    const handleEnd = () => {
        handlePlay()
        console.log('播放结束')
    }

    return {
        aduio, setbacksBox, currentTime, progress, duration, isPlay, handlePlay, handleBacks, handleTimeUpdate, handleCanPlay, handleEnd
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值