<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
用Vue3實現一個簡易的音樂播放器元件
其效果圖如下所示:
實現這個元件需要提前做的準備:
ElementUI
ElementUI的引入可以參照其官網的引入方式;
位元組跳動圖示庫
元件的【上一首】【播放】【下一首】【音量】等圖示都是來源自這個圖示庫,這是其安裝檔案
在main.js中,我是這樣引入的:
//引入位元組跳動圖示庫 import {install} from '@icon-park/vue-next/es/all'; import '@icon-park/vue-next/styles/index.css'; ...... //這種載入方式進行載入的話,代表使用預設的字首進行載入:icon //也就是說假如要使用一個主頁圖示,使用圖示時標籤該這麼寫: //<icon-home theme="outline" size="24" fill="#FFFFFF" :strokeWidth="2"/> //install(app,'prefix') 用這種方式進行載入的話,可以自定義使用圖示庫時的標籤字首 install(app)
唱見圖片
音樂源
將要播放的音樂放到檔案伺服器上,我這裡是使用阿里雲的OSS服務進行音樂檔案的儲存,然後在整個頁面載入時【也就是在onMounted生命週期函數中獲取這些資料來源】。在後面的程式碼中,這一步體現在:
//初始化歌曲源 const initMusicArr = () => { requests.get("/Music/QueryAllMusic").then(function (res) { musicState.musicArr = res musicState.musicCount = res.length }) } onMounted(() => { initMusicArr() ...... })
<template> <!--音樂播放器--> <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> <!--進度條--> <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請求,可以將這裡替換成自己的請求邏輯 import requests from "@/api/ajax"; export default { name: "index", setup() { //是否正在播放 const playState = ref(false); //現在的播放時間 const playTime = ref(0.00); //歌曲的時間長度 const playDuration = ref(0.00); //進度條長度 const sliderLength = ref(100); //歌曲URL const musicUrl = ref(""); //播放器標籤 const musicAudio = ref(null); //實現音樂播放的標籤 const musicSource = ref(null); //是否靜音 const voiceMute = ref(false); //音量大小 const voicePower = ref(0.5); const musicState = reactive({ musicArr: [], musicCount: 0 }) const musicCursor = ref(0); //頁面偏移量 const pageOffset = ref(0) //是否達到閾值,達到閾值就顯示播放器,反之 const offsetThreshold = ref(false) //啟用播放器 const operateMusicPlayer = () => { pageOffset.value = window.scrollY //當頁面捲動偏移達到800,啟用使用者方塊 if (pageOffset.value > 800) { offsetThreshold.value = true } else { //反之 offsetThreshold.value = false } } //播放按鈕點選回撥 const playButtonClick = () => { if (playState.value) { musicAudio.value.pause() } else { musicAudio.value.play() } //修改播放時間【設定這個,當一首歌正常播放結束之後,再次點選播放按鈕,進度條會得到重置】 playTime.value = musicAudio.value.currentTime //重新設定播放狀態 playState.value = !playState.value } //上一曲按鈕點選回撥 const lastButtonClick = () => { musicCursor.value -= 1 changeMusic() } //下一曲按鈕點選回撥 const nextButtonClick = () => { musicCursor.value += 1 changeMusic() } //歌曲進度條文字提示 const tooltipFormat = (val) => { let strTime = playTime.value let strMinute = parseInt(strTime / 60 + '') let strSecond = parseInt(strTime % 60 + '') return strMinute + ":" + strSecond } //當歌曲能播放時【亦即在canplay勾點函數中】,musicAudio.value.duration才不會是NaN,才能進行歌曲長度的設定 const changeDuration = () => { if (playDuration.value != musicAudio.value.duration) { //修改進度條的最大值 sliderLength.value = musicAudio.value.duration //修改歌曲播放時間 playDuration.value = musicAudio.value.duration } } //el-slider的勾點函數,拖動進度條時快進歌曲,改變當前播放進度 const changePlayTime = (val) => { musicAudio.value.currentTime = val } //音量按鈕點選回撥 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的勾點函數,用於調節音量 const changeVoicePower = (val) => { musicAudio.value.volume = val voicePower.value = val if (val > 0) { voiceMute.value = false } else { voiceMute.value = true } } //播放狀態下,進度條裡的數值每秒遞增。而Audio因為在播放狀態下,currentTime會自己遞增,所以不用處理 const updatePlayTimePerSecond = () => { if (playState.value) { playTime.value += 1 if (playTime.value >= playDuration.value) { //代表當前歌曲已經播放完畢,進行切歌 musicCursor.value++ changeMusic() } } } //切歌 const changeMusic = () => { //切歌【這裡的music_url是後端返回給前端的json字串中,用於儲存歌曲線上連結的屬性名是:music_url,所以要實現自己的請求邏輯,將這裡的music_url改為自己的即可】 musicSource.value.src = musicState.musicArr[musicCursor.value % musicState.musicCount].music_url // 當重新整理了url之後,需要執行load方法才能播放這個音樂 musicAudio.value.load() playTime.value = musicAudio.value.currentTime sliderLength.value = musicAudio.value.duration musicAudio.value.play() playState.value = true } //初始化歌曲源【將這裡替換成自己的請求邏輯】 const initMusicArr = () => { requests.get("/Music/QueryAllMusic").then(function (res) { musicState.musicArr = res musicState.musicCount = res.length }) } onMounted(() => { initMusicArr() //播放狀態下,使播放進度自增1,以與Audio內建的currentTime相匹配 setInterval(updatePlayTimePerSecond, 1000) //新增捲動事件 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%; /*設定圖片不可點選*/ 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>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45