日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > HTML >内容正文

HTML

HTML5移动端音乐播放器(启蒙篇)

發(fā)布時(shí)間:2023/12/31 HTML 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HTML5移动端音乐播放器(启蒙篇) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這段時(shí)間公司一直在做一個(gè)PC的教育類單頁(yè)應(yīng)用,龐大復(fù)雜,涉及非常多H5的知識(shí),音頻就是其中的一部分。前些天偷臺(tái)風(fēng)的閑暇時(shí)寫(xiě)了一個(gè)移動(dòng)端音樂(lè)播放器,作為練手項(xiàng)目。

在線地址:請(qǐng)猛擊這里
源碼:請(qǐng)猛擊這里

注意:使用PC瀏覽最好打開(kāi)移動(dòng)設(shè)備模式,使用移動(dòng)設(shè)備瀏覽需要關(guān)閉無(wú)痕瀏覽模式(否則無(wú)法使用本地存儲(chǔ),一般瀏覽器都是默認(rèn)不開(kāi)啟),項(xiàng)目需要在本地服務(wù)器線上服務(wù)器運(yùn)行,以file:///形式的地址打開(kāi)是無(wú)法進(jìn)行ajax請(qǐng)求的,從而無(wú)法看到音樂(lè)數(shù)據(jù)。

項(xiàng)目實(shí)現(xiàn)的功能及所用知識(shí)

  • 播放器的基礎(chǔ)操作,上一首,下一首(順序播放、隨機(jī)播放、單曲循環(huán)),播放暫停,滑動(dòng)時(shí)間軸的歌詞定位

  • 初始handlebar模板渲染音樂(lè)列表數(shù)據(jù),下拉滾動(dòng)加載音樂(lè)列表數(shù)據(jù)。

  • 歌曲列表可添加喜愛(ài)音樂(lè),于下次刷新時(shí)更新喜愛(ài)音樂(lè)列表,基于HTML5本地存儲(chǔ)。

  • 布局采用rem布局,自適應(yīng)移動(dòng)端手機(jī)設(shè)備。

  • iconfont在線圖標(biāo)應(yīng)用的使用

項(xiàng)目目錄文件結(jié)構(gòu)

css:存放樣式文件
lib:?存放公共腳本庫(kù)
js:?存放項(xiàng)目腳本文件
img:?存放圖片
fonts:?項(xiàng)目字體文件
res:?項(xiàng)目音樂(lè)資源
ui:項(xiàng)目ui文件(psd)

// ============================配置變量================================ var rootPath = window.location.href.replace(/\/\w+\.\w+/, "/"); var Settings = { playmode: 0, //0列表循環(huán),1隨機(jī),2為單曲循環(huán) volume: 0.5, //音量 initNum: 10, //列表初始化歌曲數(shù) reqNum: 10 //后續(xù)請(qǐng)求歌曲數(shù) };// ============================工具函數(shù)================================ var Util = (function() { return {} })() // ============================Dom選擇器================================ var Dom = {}// ============================全局變量================================ var winH = $(window).height();var songNum = 0; //當(dāng)前列表歌曲數(shù)目 var lrcHighIndex = 0; // 歌詞高亮索引 var lrcMoveIndex = 0; // 歌詞移動(dòng)單位索引 var moveDis = 0; // 單句歌詞每次移動(dòng)距離var duration = 0; // 當(dāng)前歌曲的時(shí)間 var index = 0; //當(dāng)前播放歌曲的索引 var songInfo = null; // 當(dāng)前歌曲信息 var songModelUI = null; // 當(dāng)前歌曲UI模型 var timeArr = []; //當(dāng)前歌曲時(shí)間數(shù)組 var formatTimeArr = []; //當(dāng)前歌曲時(shí)間數(shù)組(格式化為秒數(shù))// ============================入口函數(shù)================================ function main() { initUIFrame(); var initModel = PlayerModel();var songListUI = ModelUIFrame(Dom.songListContainer); var lsongListUI = ModelUIFrame(Dom.lSongListContainer); initModel.getSongList("data/data.json", function(data) { // 生成所有歌曲列表 songListUI.renderList(data, 0, null, function() { songListUI.updateList(); }); // 生成喜愛(ài)歌曲列表 initModel.getLoveSongArr(function(lSongArr) { lsongListUI.renderList(data, 1, lSongArr); }); // 添加動(dòng)畫(huà) Util.addAnimationDelay(Dom.song); // 保存歌詞數(shù)據(jù) initModel.saveLyric(data);}); EventHandler(); } // ============================初始化UI函數(shù)================================ function initUIFrame() {} // ============================實(shí)現(xiàn)數(shù)據(jù)交互方法================================ function PlayerModel() {} // ============================模型動(dòng)態(tài)UI模塊================================ function ModelUIFrame(container) {} // ============================事件綁定模塊================================ function EventHandler() {} // 調(diào)用入口函數(shù) main();

功能點(diǎn)詳解

Handlebar.js初次渲染及滾動(dòng)加載

使用前端模板優(yōu)點(diǎn)是把數(shù)據(jù)和結(jié)構(gòu)分離出來(lái),代碼更清晰。但后來(lái)發(fā)現(xiàn)handlerbar.js似乎無(wú)法在js中示例模板對(duì)象,而html中的handlebar在初次進(jìn)入頁(yè)面便會(huì)被編譯了,因此后續(xù)添加音樂(lè)還是采用傳統(tǒng)的拼接字符串的方式,如果你有更優(yōu)雅的動(dòng)態(tài)加載方式,歡迎討論交流。

html:handlebars模板包含在script標(biāo)簽之中并且type類型為”text/x-handlebars-template”,在初始化頁(yè)面的時(shí)候根據(jù)js獲取數(shù)據(jù)植入后就渲染出相應(yīng)的html。

<script id="sListTpl" type="text/x-handlebars-template"> {{#each this}} {{#isInitData this @index}} <li class="song btm-line" data-src={{songSrc}} data-index={{id}}><div class="poster"><img src={{poster.thumbnail}}></div><div class="songinfo"><h2 class="lsongname">{{songName}}</h2><sub class="lsinger">{{singer}}</sub></div><div class="loveflag"><i class="icon icon-love {{#if loveFlag}}active{{/if}}"></i></div> </li> {{/isInitData}} {{/each}} </script>

js:

function renderAllList(data) {var preTpl;var lsongArr = Util.getItem('lsonglist') === null ? [] : JSON.parse(Util.getItem('lsonglist'));// 生成列表if (!sListTpl) {// 后續(xù)動(dòng)態(tài)生成歌曲var tpl = "";var songIndex = songNum;$.each(data, function(index, el) {if (index >= songIndex && index < songIndex + Settings.reqNum) {tpl += "<li class='song btm-line' data-src='res/music/" + songNum + ".mp3' data-index='" + songNum + "'><div class='poster'>[站外圖片上傳中……(1)]</div><div class='songinfo'><h2 class='lsongname'>" + el.songName + "</h2><sub class='lsinger'>" + el.singer + "</sub></div><div class='loveflag'><i class='icon icon-love '></i></div></li>";songNum++;}});$(container).append($(tpl));} else {// 首次生成歌曲preTpl = Handlebars.compile(sListTpl);$(container).html(preTpl(data));}// 更新喜愛(ài)圖標(biāo)if (lsongArr.length !== 0) {$.each(lsongArr, function(index, val) {Dom.songListContainer.find(".song").eq(val).find(".icon-love").addClass('active');});} }

rem布局自適應(yīng)方案

大體上指的是html根元素上定義一個(gè)字體大小,然后css樣式定義時(shí)使用rem作為單位,包括margin、paddding、用于絕對(duì)定位的單位等等。然后js根據(jù)手機(jī)設(shè)備的屏幕大小,改變根字體的大小,這樣整個(gè)頁(yè)面也會(huì)跟著相應(yīng)的縮小或放大。
更多詳解,請(qǐng)看這一篇文章《移動(dòng)端自適應(yīng)布局解決方案——rem》,您可以猛擊這里跳轉(zhuǎn)。

關(guān)于歌詞的同步方案實(shí)現(xiàn)

目前音樂(lè)播放器的歌詞同步顯示大概有兩種,一種是精確到單個(gè)文字,一種是精確到單行歌詞。本文實(shí)現(xiàn)的是第二種。

整體實(shí)現(xiàn)思路

頁(yè)面初始化時(shí),請(qǐng)求歌曲數(shù)據(jù)json(本地json文件模擬),其中歌名、歌手、圖片等按需渲染到html中,將歌詞存儲(chǔ)到localStorage中。此時(shí),F12打開(kāi)chrome調(diào)試器,進(jìn)入Application-LocalStorage可以看到:

點(diǎn)擊一首歌進(jìn)入播放頁(yè)面后,歌詞就會(huì)從本地存儲(chǔ)中讀取,此時(shí)你會(huì)看到生成這樣的歌詞結(jié)構(gòu):

每一行歌詞都將要將歌詞時(shí)間綁定在data-point上,監(jiān)聽(tīng)歌曲播放的timeupdate事件,當(dāng)歌曲的時(shí)間(經(jīng)過(guò)取整處理)與當(dāng)前data-point值相等時(shí),就為當(dāng)前歌詞高亮(相當(dāng)于給p添加current類名),并且根據(jù)當(dāng)前高亮歌詞的index索引將整個(gè)歌詞盒子向上移動(dòng)p標(biāo)簽的高度+margin-top的高度

lrc歌詞的結(jié)構(gòu)

來(lái)自網(wǎng)易云音樂(lè)的歌詞數(shù)據(jù):

[00:14.64]如果不是那鏡子\n[00:16.73]不像你不藏秘密\n[00:21.26]我還不肯相信\n[00:23.02]沒(méi)有你我的笑更美麗\n[00:28.99]那天聽(tīng)你在電話里略帶抱歉的關(guān)心\n[00:16.959]摘一顆蘋(píng)果\n[00:19.800]等你從門(mén)前經(jīng)過(guò)\n[00:22.700]送到你的手中幫你解渴\n[00:25.570]像夏天的可樂(lè)\n[00:00.00] 作曲 : 周杰倫\n[00:01.00] 作詞 : 周杰倫\n[00:05.620]\n[00:37.980]親吻你的手\n

可以看到格式 = [時(shí)間點(diǎn)] + 要顯示的文字 + \n
這里有兩個(gè)坑需要注意:
有的歌詞秒數(shù)是精確到小數(shù)點(diǎn)后兩位有的是三位
有的歌詞(周杰倫《算什么男人》)格式是[時(shí)間點(diǎn)]+\n

時(shí)間歌詞創(chuàng)建映射

首先以n將歌詞字符串分割成以[時(shí)間點(diǎn)]文字的數(shù)組,但由于這樣分割之后最后一個(gè)元素是空的,所以用tempArr.splice(-1, 1)刪除最后一個(gè)元素。
接下來(lái)循環(huán)遍歷這個(gè)臨時(shí)數(shù)組,由于上面提到的秒數(shù)精確度的問(wèn)題,所以判斷一下index為9是否為數(shù)字,若為數(shù)字則將該位數(shù)字刪除。(采用字符串截取方式,若你對(duì)js字符串方法不熟悉,可以猛擊這里)
經(jīng)過(guò)這樣的處理之后,臨時(shí)數(shù)組的元素格式不再有區(qū)別了,此時(shí)再進(jìn)行字符串截取,將截取到的時(shí)間點(diǎn)放入timeArr,將截取的歌詞放入lyricArr,并以返回保存著這兩個(gè)變量的對(duì)象。

function createArrMap(lyric) {var timeArr = [],lyricArr = [];var tempArr = lyric.split("\n");tempArr.splice(-1, 1);var tempStr = "";$(tempArr).each(function(index) {tempStr = this;if (tempStr.charAt(9).match(/\d/) !== null) {tempStr = tempStr.substring(0, 9) + tempStr.substring(10);}timeArr.push(tempStr.substring(0, 10));lyricArr.push(tempStr.substring(10));});return {timeArr: timeArr,lyricArr: lyricArr}; }

生成歌詞

由于上面歌詞格式造成時(shí)間點(diǎn)對(duì)應(yīng)的歌詞為空,此時(shí)如果渲染出一個(gè)
標(biāo)簽的高度將為0,這會(huì)影響歌詞向上移動(dòng)距離的不統(tǒng)一。因此下面作出個(gè)判斷如果為空,則替換為“————–”。(為空的時(shí)候大多數(shù)是歌曲中間停頓或過(guò)渡的時(shí)候)

function renderLyric(songinfo) {var arrMap = Util.createArrMap(songinfo.lyric);var tpl = "";$.each(arrMap.lyricArr, function(index, lyric) {var lyricContent = lyric === "" ? "--------------" : lyric;tpl += "<p class='' data-point='" + arrMap.timeArr[index] + "'>" + lyricContent + "</p>";});Dom.lrcwrap.html(tpl); }

歌詞同步

歌詞同步我寫(xiě)在了syncLyric方法中,監(jiān)聽(tīng)audio元素的timeupdate事件調(diào)用。
這個(gè)方法接收兩個(gè)參數(shù),第一個(gè)是當(dāng)前播放歌曲時(shí)間(秒),第二個(gè)是轉(zhuǎn)化為秒數(shù)的時(shí)間點(diǎn)數(shù)組。
如果當(dāng)前時(shí)間>=時(shí)間點(diǎn),那么高亮當(dāng)前歌詞(以lrcHighIndex)存儲(chǔ),并且lrcHighIndex自增1。
當(dāng)歌詞高亮索引lrcHighIndex>=1即歌詞高亮不為第一句時(shí),計(jì)算索引并讓歌詞盒子向上移動(dòng)。

function syncLyric(curS, formatTimeArr) {if (Math.floor(curS) >= formatTimeArr[lrcHighIndex]) {Dom.lrc.eq(lrcHighIndex).addClass('current').siblings().removeClass('current');if (lrcHighIndex >= 1) {lrcMoveIndex = lrcHighIndex - 2;moveDis += Util.getMoveDis(lrcMoveIndex);Dom.lrcwrap.animate({"top": "-" + moveDis + "px"}, 100);lrcMoveIndex++;}lrcHighIndex++;} }

總結(jié)

以上是生活随笔為你收集整理的HTML5移动端音乐播放器(启蒙篇)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。