欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3實(shí)現(xiàn)簡(jiǎn)易音樂(lè)播放器組件

 更新時(shí)間:2022年08月14日 11:30:52   作者:cb414  
這篇文章主要為大家詳細(xì)介紹了Vue3實(shí)現(xiàn)簡(jiǎn)易音樂(lè)播放器組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

用Vue3實(shí)現(xiàn)一個(gè)簡(jiǎn)易的音樂(lè)播放器組件

其效果圖如下所示:

實(shí)現(xiàn)這個(gè)組件需要提前做的準(zhǔn)備:

  • 引入ElementUI
  • 引入字節(jié)跳動(dòng)圖標(biāo)庫(kù)
  • 一張唱見(jiàn)圖片
  • 將要播放的音樂(lè)上傳到文件服務(wù)器上,并提供一個(gè)能在線(xiàn)訪(fǎng)問(wèn)的鏈接【這里使用的是阿里云的OSS服務(wù)】

準(zhǔn)備

ElementUI

ElementUI的引入可以參照其官網(wǎng)的引入方式;

字節(jié)跳動(dòng)圖標(biāo)庫(kù)

組件的【上一首】【播放】【下一首】【音量】等圖標(biāo)都是來(lái)源自這個(gè)圖標(biāo)庫(kù),這是其安裝文檔

在main.js中,我是這樣引入的:

//引入字節(jié)跳動(dòng)圖標(biāo)庫(kù)
import {install} from '@icon-park/vue-next/es/all';
import '@icon-park/vue-next/styles/index.css';

......

//這種加載方式進(jìn)行加載的話(huà),代表使用默認(rèn)的前綴進(jìn)行加載:icon
//也就是說(shuō)假如要使用一個(gè)主頁(yè)圖標(biāo),使用圖標(biāo)時(shí)標(biāo)簽該這么寫(xiě):?
//<icon-home theme="outline" size="24" fill="#FFFFFF" :strokeWidth="2"/>
//install(app,'prefix') 用這種方式進(jìn)行加載的話(huà),可以自定義使用圖標(biāo)庫(kù)時(shí)的標(biāo)簽前綴
install(app)

唱見(jiàn)圖片

音樂(lè)源

將要播放的音樂(lè)放到文件服務(wù)器上,我這里是使用阿里云的OSS服務(wù)進(jìn)行音樂(lè)文件的存儲(chǔ),然后在整個(gè)頁(yè)面加載時(shí)【也就是在onMounted生命周期函數(shù)中獲取這些數(shù)據(jù)源】。在后面的代碼中,這一步體現(xiàn)在:

//初始化歌曲源
const initMusicArr = () => {
? ? ? ? requests.get("/Music/QueryAllMusic").then(function (res) {
? ? ? ? ? ? musicState.musicArr = res

? ? ? ? ? ? musicState.musicCount = res.length
? ? ? ? })
? ? }

? ? onMounted(() => {
? ? ? ? initMusicArr()

? ? ? ? ? ? ......
? ? })

完整代碼

<template>

? <!--音樂(lè)播放器-->
? <div class="music-container" :class="{'music-active-switch': offsetThreshold}">
? ? <div class="music-disk">
? ? ? <!--唱片圖片-->
? ? ? <img class="music-disk-picture" :class="{'music-disk-playing-style': playState}" src="./images/R-C.png"
? ? ? ? ? ?alt="">
? ? </div>

? ? <!--進(jìn)度條-->
? ? <div class="music-slider">
? ? ? <el-slider
? ? ? ? ? v-model="playTime"
? ? ? ? ? :format-tooltip="tooltipFormat"
? ? ? ? ? size="small"
? ? ? ? ? :max="sliderLength"
? ? ? ? ? @change="changePlayTime"/>
? ? </div>

? ? <!--按鈕組-->
? ? <div class="button-group">
? ? ? <!--上一曲 按鈕-->
? ? ? <button class="play-button" @click="lastButtonClick">
? ? ? ? <icon-go-start theme="outline" size="23" fill="#939393" :strokeWidth="3" strokeLinejoin="miter"
? ? ? ? ? ? ? ? ? ? ? ?strokeLinecap="butt"/>
? ? ? </button>
? ? ? <!--播放 按鈕-->
? ? ? <button class="play-button" @click="playButtonClick">
? ? ? ? <icon-play-one v-if="!playState" theme="outline" size="23" fill="#939393" :strokeWidth="3"
? ? ? ? ? ? ? ? ? ? ? ?strokeLinejoin="miter" strokeLinecap="butt"/>
? ? ? ? <icon-pause v-if="playState" theme="outline" size="23" fill="#939393" :strokeWidth="3"
? ? ? ? ? ? ? ? ? ? strokeLinejoin="miter" strokeLinecap="butt"/>
? ? ? </button>
? ? ? <!--下一曲 按鈕-->
? ? ? <button class="play-button" @click="nextButtonClick">
? ? ? ? <icon-go-end theme="outline" size="23" fill="#939393" :strokeWidth="3" strokeLinejoin="miter"
? ? ? ? ? ? ? ? ? ? ?strokeLinecap="butt"/>
? ? ? </button>
? ? ? <!--音量按鈕-->
? ? ? <div class="voice-container">
? ? ? ? <button class="voice-button" @click="voiceButtonClick">
? ? ? ? ? <icon-volume-notice v-if="!voiceMute" theme="outline" size="23" fill="#939393" :strokeWidth="3"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? strokeLinejoin="miter" strokeLinecap="butt"/>
? ? ? ? ? <icon-volume-mute v-if="voiceMute" theme="outline" size="23" fill="#939393" :strokeWidth="3"
? ? ? ? ? ? ? ? ? ? ? ? ? ? strokeLinejoin="miter" strokeLinecap="butt"/>
? ? ? ? </button>
? ? ? ? <div class="voice-slider">
? ? ? ? ? <el-slider
? ? ? ? ? ? ? v-model="voicePower"
? ? ? ? ? ? ? :max="1"
? ? ? ? ? ? ? :step="0.1"
? ? ? ? ? ? ? size="small"
? ? ? ? ? ? ? @change="changeVoicePower"/>
? ? ? ? </div>
? ? ? </div>
? ? </div>

? ? <audio
? ? ? ? ref="musicAudio"
? ? ? ? class="audio-component"
? ? ? ? controls
? ? ? ? preload="auto"
? ? ? ? @canplay="changeDuration">
? ? ? <source ref="musicSource" type="audio/mpeg"/>
? ? </audio>
? </div>

</template>

<script>
import {computed, onMounted, onUnmounted, reactive, ref, watch} from "vue";

//這里是自己封裝的axios請(qǐng)求,可以將這里替換成自己的請(qǐng)求邏輯
import requests from "@/api/ajax";

export default {
? name: "index",
? setup() {

? ? //是否正在播放
? ? const playState = ref(false);

? ? //現(xiàn)在的播放時(shí)間
? ? const playTime = ref(0.00);

? ? //歌曲的時(shí)間長(zhǎng)度
? ? const playDuration = ref(0.00);

? ? //進(jìn)度條長(zhǎng)度
? ? const sliderLength = ref(100);

? ? //歌曲URL
? ? const musicUrl = ref("");

? ? //播放器標(biāo)簽
? ? const musicAudio = ref(null);

? ? //實(shí)現(xiàn)音樂(lè)播放的標(biāo)簽
? ? const musicSource = ref(null);

? ? //是否靜音
? ? const voiceMute = ref(false);

? ? //音量大小
? ? const voicePower = ref(0.5);

? ? const musicState = reactive({
? ? ? musicArr: [],
? ? ? musicCount: 0
? ? })

? ? const musicCursor = ref(0);

? ? //頁(yè)面偏移量
? ? const pageOffset = ref(0)

? ? //是否達(dá)到閾值,達(dá)到閾值就顯示播放器,反之
? ? const offsetThreshold = ref(false)

? ? //激活播放器
? ? const operateMusicPlayer = () => {
? ? ? pageOffset.value = window.scrollY
? ? ? //當(dāng)頁(yè)面滾動(dòng)偏移達(dá)到800,激活用戶(hù)框
? ? ? if (pageOffset.value > 800) {
? ? ? ? offsetThreshold.value = true
? ? ? } else {
? ? ? ? //反之
? ? ? ? offsetThreshold.value = false
? ? ? }
? ? }

? ? //播放按鈕點(diǎn)擊回調(diào)
? ? const playButtonClick = () => {

? ? ? if (playState.value) {
? ? ? ? musicAudio.value.pause()
? ? ? } else {
? ? ? ? musicAudio.value.play()
? ? ? }

? ? ? //修改播放時(shí)間【設(shè)置這個(gè),當(dāng)一首歌正常播放結(jié)束之后,再次點(diǎn)擊播放按鈕,進(jìn)度條會(huì)得到重置】
? ? ? playTime.value = musicAudio.value.currentTime

? ? ? //重新設(shè)置播放狀態(tài)
? ? ? playState.value = !playState.value
? ? }

? ? //上一曲按鈕點(diǎn)擊回調(diào)
? ? const lastButtonClick = () => {
? ? ? musicCursor.value -= 1

? ? ? changeMusic()
? ? }

? ? //下一曲按鈕點(diǎn)擊回調(diào)
? ? const nextButtonClick = () => {
? ? ? musicCursor.value += 1

? ? ? changeMusic()
? ? }

? ? //歌曲進(jìn)度條文本提示
? ? const tooltipFormat = (val) => {

? ? ? let strTime = playTime.value

? ? ? let strMinute = parseInt(strTime / 60 + '')

? ? ? let strSecond = parseInt(strTime % 60 + '')

? ? ? return strMinute + ":" + strSecond
? ? }

? ? //當(dāng)歌曲能播放時(shí)【亦即在canplay鉤子函數(shù)中】,musicAudio.value.duration才不會(huì)是NaN,才能進(jìn)行歌曲長(zhǎng)度的設(shè)置
? ? const changeDuration = () => {
? ? ? if (playDuration.value != musicAudio.value.duration) {

? ? ? ? //修改進(jìn)度條的最大值
? ? ? ? sliderLength.value = musicAudio.value.duration

? ? ? ? //修改歌曲播放時(shí)間
? ? ? ? playDuration.value = musicAudio.value.duration
? ? ? }
? ? }

? ? //el-slider的鉤子函數(shù),拖動(dòng)進(jìn)度條時(shí)快進(jìn)歌曲,改變當(dāng)前播放進(jìn)度
? ? const changePlayTime = (val) => {
? ? ? musicAudio.value.currentTime = val
? ? }

? ? //音量按鈕點(diǎn)擊回調(diào)
? ? const voiceButtonClick = () => {
? ? ? voiceMute.value = !voiceMute.value

? ? ? if (!voiceMute.value) {
? ? ? ? voicePower.value = 1

? ? ? ? musicAudio.value.volume = 1
? ? ? } else {
? ? ? ? voicePower.value = 0

? ? ? ? musicAudio.value.volume = 0
? ? ? }
? ? }

? ? //el-slider的鉤子函數(shù),用于調(diào)節(jié)音量
? ? const changeVoicePower = (val) => {
? ? ? musicAudio.value.volume = val

? ? ? voicePower.value = val

? ? ? if (val > 0) {
? ? ? ? voiceMute.value = false
? ? ? } else {
? ? ? ? voiceMute.value = true
? ? ? }

? ? }

? ? //播放狀態(tài)下,進(jìn)度條里的數(shù)值每秒遞增。而Audio因?yàn)樵诓シ艩顟B(tài)下,currentTime會(huì)自己遞增,所以不用處理
? ? const updatePlayTimePerSecond = () => {
? ? ? if (playState.value) {
? ? ? ? playTime.value += 1

? ? ? ? if (playTime.value >= playDuration.value) {
? ? ? ? ? //代表當(dāng)前歌曲已經(jīng)播放完畢,進(jìn)行切歌
? ? ? ? ? musicCursor.value++

? ? ? ? ? changeMusic()
? ? ? ? }
? ? ? }
? ? }

? ? //切歌
? ? const changeMusic = () => {
? ? ? //切歌【這里的music_url是后端返回給前端的json字符串中,用于存儲(chǔ)歌曲在線(xiàn)鏈接的屬性名是:music_url,所以要實(shí)現(xiàn)自己的請(qǐng)求邏輯,將這里的music_url改為自己的即可】
? ? ? musicSource.value.src = musicState.musicArr[musicCursor.value % musicState.musicCount].music_url

? ? ? // 當(dāng)刷新了url之后,需要執(zhí)行l(wèi)oad方法才能播放這個(gè)音樂(lè)
? ? ? musicAudio.value.load()

? ? ? playTime.value = musicAudio.value.currentTime

? ? ? sliderLength.value = musicAudio.value.duration

? ? ? musicAudio.value.play()

? ? ? playState.value = true
? ? }

? ? //初始化歌曲源【將這里替換成自己的請(qǐng)求邏輯】
? ? const initMusicArr = () => {
? ? ? requests.get("/Music/QueryAllMusic").then(function (res) {
? ? ? ? musicState.musicArr = res

? ? ? ? musicState.musicCount = res.length

? ? ? })
? ? }

? ? onMounted(() => {
? ? ? initMusicArr()

? ? ? //播放狀態(tài)下,使播放進(jìn)度自增1,以與Audio內(nèi)置的currentTime相匹配
? ? ? setInterval(updatePlayTimePerSecond, 1000)

? ? ? //添加滾動(dòng)事件
? ? ? window.addEventListener("scroll", operateMusicPlayer)
? ? })

? ? onUnmounted(() => {
? ? ? window.removeEventListener("scroll", operateMusicPlayer)
? ? })


? ? return {
? ? ? musicAudio,
? ? ? musicSource,
? ? ? playState,
? ? ? playTime,
? ? ? playDuration,
? ? ? sliderLength,
? ? ? musicUrl,
? ? ? voiceMute,
? ? ? voicePower,
? ? ? musicState,
? ? ? musicCursor,
? ? ? pageOffset,
? ? ? offsetThreshold,
? ? ? playButtonClick,
? ? ? lastButtonClick,
? ? ? nextButtonClick,
? ? ? voiceButtonClick,
? ? ? tooltipFormat,
? ? ? changeMusic,
? ? ? changeDuration,
? ? ? changePlayTime,
? ? ? changeVoicePower,
? ? ? updatePlayTimePerSecond,
? ? ? initMusicArr
? ? }
? },
}
</script>

<style scoped>

.music-container {
? position: fixed;
? justify-content: center;
? width: 280px;
? height: 110px;
? background-color: white;
? border-radius: 15px;
? bottom: 15px;
? left: 10px;
? opacity: 0;
? transition: 0.5s;
}


.music-disk {
? position: absolute;
? width: 90px;
? height: 90px;
? left: 15px;
? top: 10px;
? border-radius: 50%;
}

.music-disk-picture {
? width: 90px;
? height: 90px;
? border-radius: 50%;
? /*設(shè)置圖片不可點(diǎn)擊*/
? pointer-events: none;
}

.music-disk-playing-style {
? animation: music-disk-rotate 5s linear infinite;
}

@keyframes music-disk-rotate {
? 0% {
? ? transform: rotate(0deg);
? }
? 100% {
? ? transform: rotate(360deg);
? }
}

.button-group {
? position: absolute;
? width: 330px;
? height: 38px;
? left: 90px;
? bottom: 13px;
? margin-left: 10px;
}

.button-group > button {
? margin-left: 10px;
}

.play-button {
? float: left;
? width: 31px;
? height: 31px;
? padding: 4px;
? /*margin: 0px;*/
? border: 0px;
? border-radius: 50%;
? margin: 7px 0px 0px 0px;
}

.voice-button {
? float: left;
? width: 31px;
? height: 31px;
? padding: 0px;
? /*margin: 0px;*/
? border: 0px;
? border-radius: 50%;
? margin: 7px 0px 0px 0px;
? background-color: transparent;
}


.music-slider {
? position: absolute;
? top: 20px;
? left: 120px;
? width: 50%;
}

.voice-container {
? float: left;
? margin-left: 12px;
? width: 31px;
? height: 38px;
? overflow: hidden !important;
? transition: 0.5s;
}

.voice-container:hover {
? width: 160px;
}


.voice-slider {
? position: relative;
? top: 2px;
? right: -30px;
? width: 90px;
? height: 35px;
? background-color: white;
? border-radius: 10px;
? padding: 0px 15px 0px 15px;
? transition: 0.2s;
}

.audio-component {
? width: 300px;
? height: 200px;
? top: 100px;
? display: none;
}

.music-active-switch{
? opacity: 1;
}

</style>

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue3使用viewer的詳細(xì)用法舉例

    vue3使用viewer的詳細(xì)用法舉例

    viewer.js用于圖片瀏覽的Vue組件,支持旋轉(zhuǎn)、縮放、翻轉(zhuǎn)等操作,這篇文章主要給大家介紹了關(guān)于vue3使用viewer的詳細(xì)用法,文中通過(guò)代碼介紹是非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • vue使用element-ui的el-image的問(wèn)題分析

    vue使用element-ui的el-image的問(wèn)題分析

    這篇文章主要介紹了vue使用element-ui的el-image的問(wèn)題分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 如何抽象一個(gè)Vue公共組件

    如何抽象一個(gè)Vue公共組件

    這篇文章主要介紹了如何抽象一個(gè)Vue公共組件,以一個(gè)數(shù)字鍵盤(pán)組件為例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • antd?vue?表格rowSelection選擇框功能的使用方式

    antd?vue?表格rowSelection選擇框功能的使用方式

    這篇文章主要介紹了antd?vue?表格rowSelection選擇框功能的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
    2022-12-12
  • vue3中defineComponent?的作用詳解

    vue3中defineComponent?的作用詳解

    這篇文章主要介紹了vue3中defineComponent?的作用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • Vue SPA首屏加載緩慢問(wèn)題解決方案

    Vue SPA首屏加載緩慢問(wèn)題解決方案

    這篇文章主要介紹了Vue SPA首屏加載緩慢問(wèn)題解決方案,首屏?xí)r間(First Contentful Paint),指的是瀏覽器從響應(yīng)用戶(hù)輸入網(wǎng)址地址,到首屏內(nèi)容渲染完成的時(shí)間,此時(shí)整個(gè)網(wǎng)頁(yè)不一定要全部渲染完成,但需要展示當(dāng)前視窗需要的內(nèi)容
    2023-03-03
  • vue-calendar-component日歷組件報(bào)錯(cuò)Clock is not defined解決

    vue-calendar-component日歷組件報(bào)錯(cuò)Clock is not defi

    這篇文章主要為大家介紹了vue-calendar-component日歷組件報(bào)錯(cuò)Clock is not defined解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 微信小程序?qū)崙?zhàn)基于vue2實(shí)現(xiàn)瀑布流的代碼實(shí)例

    微信小程序?qū)崙?zhàn)基于vue2實(shí)現(xiàn)瀑布流的代碼實(shí)例

    瀑布流,又稱(chēng)瀑布流式布局,是比較流行的一種網(wǎng)站頁(yè)面布局,視覺(jué)表現(xiàn)為參差不齊的多欄布局,隨著頁(yè)面滾動(dòng)條向下滾動(dòng),這種布局還會(huì)不斷加載數(shù)據(jù)塊并附加至當(dāng)前尾部,這篇文章主要介紹了微信小程序?qū)崙?zhàn),基于vue2實(shí)現(xiàn)瀑布流,需要的朋友可以參考下
    2022-12-12
  • vue計(jì)算屬性時(shí)v-for處理數(shù)組時(shí)遇到的一個(gè)bug問(wèn)題

    vue計(jì)算屬性時(shí)v-for處理數(shù)組時(shí)遇到的一個(gè)bug問(wèn)題

    這篇文章主要介紹了在做vue計(jì)算屬性,v-for處理數(shù)組時(shí)遇到的一個(gè)bug 問(wèn)題,需要的朋友可以參考下
    2018-01-01
  • vue3中通過(guò)ref獲取元素節(jié)點(diǎn)的實(shí)現(xiàn)

    vue3中通過(guò)ref獲取元素節(jié)點(diǎn)的實(shí)現(xiàn)

    這篇文章主要介紹了vue3中通過(guò)ref獲取元素節(jié)點(diǎn)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評(píng)論