这段时间公司一直在做一个PC的教育类单页应用,庞大复杂,涉及非常多H5的知识,音频就是其中的一部分。前些天偷台风的闲暇时写了一个移动音乐播放器,作为练手项目(存放在码云)。若你觉得该文章对你有帮助,别忘了点个赞啦。

**在线地址:**请猛击这里
**源码:**请猛击这里

注意:使用PC浏览最好打开移动设备模式,使用移动设备浏览需要关闭无痕浏览模式(否则无法使用本地存储,一般浏览器都是默认不开启),项目需要在本地服务器线上服务器运行,以file:///形式的地址打开是无法进行ajax请求的,从而无法看到音乐数据。

项目实现的功能及所用知识

  • 播放器的基础操作,上一首,下一首(顺序播放、随机播放、单曲循环),播放暂停,滑动时间轴的歌词定位
  • 初始handlebar模板渲染音乐列表数据,下拉滚动加载音乐列表数据。
  • 歌曲列表可添加喜爱音乐,于下次刷新时更新喜爱音乐列表,基于HTML5本地存储。
  • 布局采用rem布局,自适应移动端手机设备。
  • iconfont在线图标应用的使用

项目目录文件结构
**css:**存放样式文件
**lib:**存放公共脚本库
**js:**存放项目脚本文件
**img:**存放图片
**fonts:**项目字体文件
**res:**项目音乐资源
**ui:**项目ui文件(psd)

// ============================配置变量================================
var rootPath = window.location.href.replace(/\/\w+\.\w+/, "/");
var Settings = {
playmode: 0, //0列表循环,1随机,2为单曲循环
volume: 0.5, //音量
initNum: 10, //列表初始化歌曲数
reqNum: 10 //后续请求歌曲数
};// ============================工具函数================================
var Util = (function() {
return {}
})()
// ============================Dom选择器================================
var Dom = {}// ============================全局变量================================
var winH = $(window).height();var songNum = 0; //当前列表歌曲数目
var lrcHighIndex = 0; // 歌词高亮索引
var lrcMoveIndex = 0; // 歌词移动单位索引
var moveDis = 0; // 单句歌词每次移动距离var duration = 0; // 当前歌曲的时间
var index = 0; //当前播放歌曲的索引
var songInfo = null; // 当前歌曲信息
var songModelUI = null; // 当前歌曲UI模型
var timeArr = []; //当前歌曲时间数组
var formatTimeArr = []; //当前歌曲时间数组(格式化为秒数)// ============================入口函数================================
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();
});
// 生成喜爱歌曲列表
initModel.getLoveSongArr(function(lSongArr) {
lsongListUI.renderList(data, 1, lSongArr);
});
// 添加动画
Util.addAnimationDelay(Dom.song);
// 保存歌词数据
initModel.saveLyric(data);});
EventHandler();
}
// ============================初始化UI函数================================
function initUIFrame() {}
// ============================实现数据交互方法================================
function PlayerModel() {}
// ============================模型动态UI模块================================
function ModelUIFrame(container) {}
// ============================事件绑定模块================================
function EventHandler() {}
// 调用入口函数
main();

功能点详解
Handlebar.js初次渲染及滚动加载
使用前端模板优点是把数据和结构分离出来,代码更清晰。但后来发现handlerbar.js似乎无法在js中示例模板对象,而html中的handlebar在初次进入页面便会被编译了,因此后续添加音乐还是采用传统的拼接字符串的方式,如果你有更优雅的动态加载方式,欢迎讨论交流。

**html:**handlebars模板包含在script标签之中并且type类型为”text/x-handlebars-template”,在初始化页面的时候根据js获取数据植入后就渲染出相应的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) {// 后续动态生成歌曲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));}// 更新喜爱图标if (lsongArr.length !== 0) {$.each(lsongArr, function(index, val) {Dom.songListContainer.find(".song").eq(val).find(".icon-love").addClass('active');});}
}

rem布局自适应方案
大体上指的是html根元素上定义一个字体大小,然后css样式定义时使用rem作为单位,包括margin、paddding、用于绝对定位的单位等等。然后js根据手机设备的屏幕大小,改变根字体的大小,这样整个页面也会跟着相应的缩小或放大。
更多详解,请看这一篇文章《移动端自适应布局解决方案——rem》,您可以猛击这里跳转。

关于歌词的同步方案实现
目前音乐播放器的歌词同步显示大概有两种,一种是精确到单个文字,一种是精确到单行歌词。本文实现的是第二种。

整体实现思路
页面初始化时,请求歌曲数据json(本地json文件模拟),其中歌名、歌手、图片等按需渲染到html中,将歌词存储到localStorage中。此时,F12打开chrome调试器,进入Application-LocalStorage可以看到:

点击一首歌进入播放页面后,歌词就会从本地存储中读取,此时你会看到生成这样的歌词结构:

每一行歌词都将要将歌词时间绑定在data-point上,监听歌曲播放的timeupdate事件,当歌曲的时间(经过取整处理)与当前data-point值相等时,就为当前歌词高亮(相当于给p添加current类名),并且根据当前高亮歌词的index索引将整个歌词盒子向上移动p标签的高度+margin-top的高度

lrc歌词的结构
来自网易云音乐的歌词数据:

[00:14.64]如果不是那镜子\n[00:16.73]不像你不藏秘密\n[00:21.26]我还不肯相信\n[00:23.02]没有你我的笑更美丽\n[00:28.99]那天听你在电话里略带抱歉的关心\n[00:16.959]摘一颗苹果\n[00:19.800]等你从门前经过\n[00:22.700]送到你的手中帮你解渴\n[00:25.570]像夏天的可乐\n[00:00.00] 作曲 : 周杰伦\n[00:01.00] 作词 : 周杰伦\n[00:05.620]\n[00:37.980]亲吻你的手\n

可以看到格式 = [时间点] + 要显示的文字 + \n
这里有两个坑需要注意:
有的歌词秒数是精确到小数点后两位有的是三位
有的歌词(周杰伦《算什么男人》)格式是**[时间点]+\n**

时间歌词创建映射
首先以\n将歌词字符串分割成以**[时间点]文字的数组,但由于这样分割之后最后一个元素是空的,所以用tempArr.splice(-1, 1)**删除最后一个元素。
接下来循环遍历这个临时数组,由于上面提到的秒数精确度的问题,所以判断一下index为9是否为数字,若为数字则将该位数字删除。(采用字符串截取方式,若你对js字符串方法不熟悉,可以猛击这里)
经过这样的处理之后,临时数组的元素格式不再有区别了,此时再进行字符串截取,将截取到的时间点放入timeArr,将截取的歌词放入lyricArr,并以返回保存着这两个变量的对象。

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};
}

生成歌词
由于上面歌词格式造成时间点对应的歌词为空,此时如果渲染出一个
标签的高度将为0,这会影响歌词向上移动距离的不统一。因此下面作出个判断如果为空,则替换为“————–”。(为空的时候大多数是歌曲中间停顿或过渡的时候)

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);
}

歌词同步
歌词同步我写在了syncLyric方法中,监听audio元素的timeupdate事件调用。
这个方法接收两个参数,第一个是当前播放歌曲时间(秒),第二个是转化为秒数的时间点数组。
如果当前时间>=时间点,那么高亮当前歌词(以lrcHighIndex)存储,并且lrcHighIndex自增1。
当歌词高亮索引lrcHighIndex>=1即歌词高亮不为第一句时,计算索引并让歌词盒子向上移动。

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++;}
}

PS:更多前端资讯、技术干货,请关注公众号「前端新视界」,后台回复 “1” 获取100本PDF前端电子书
回复 “2” 获取小编精选的Python编程电子书

如何快速做一个HTML5移动播放器相关推荐

  1. html中加入音乐播放器,4个小时实现一个HTML5音乐播放器

    技术点:ES6+Webpack+HTML5 Audio+Sass 这里,我们将一步步的学到如何从零去实现一个H5音乐播放器. 首先来看一下最终的实现效果:Demo链接 => 界面: skPlay ...

  2. matlab中GUI的属性检查器中的XLimMode是什么_如何在Matlab中使用GUI做一个简易音乐播放器? ---- (二)GUIDE...

    咕咕怪由于昨天有重要的事情所以咕了一天的文章 (感觉写得挺基础的,对各个部分有一定了解的童鞋可以直接跳过了解的部分 用Matlab做一个app有几种办法呢? 同样的,帮助文档告诉了我们答案:三种. 英 ...

  3. matlab figure函数_如何在Matlab中使用GUI做一个简易音乐播放器? ---- (六)控件间的数据传递...

    我纠结了两个星期是否要写这一章-最后决定还是要写一章收尾,来解释其中的控件间的数据传递问题. 在前五篇中,如果有童鞋跟上了我的思路或者做完了这样一个gui,会发现还有一个一直避开的遗留问题,就是将歌曲 ...

  4. 教你自己做一个自定义的播放器 支持全屏,不支持窗口最大化、取消全屏

    v1: 最简单的视频播放器: from PyQt5.QtWidgets import QApplication, QFileDialog from PyQt5.QtMultimedia import ...

  5. jmfapplet做一个简单的播放器

    做一个项目,客户要求播放某一时刻的影像or动画, 于是想到了jmf+applet.jar包地址如下: http://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/ ...

  6. python如何播放视频_如何用python做一个视频搜索+播放器

    import urllib.request import json import requests import re import tkinter as tk import tkinter.mess ...

  7. 百度音乐接口-——可以根据这做一个在线音乐播放器哦

    当你在百度去搜索一首歌时,你会发现有种更简单的方法,嘿嘿,安宁ヤ太天真告诉你个秘密, 百度有个不公开的API http://box.zhangmen.baidu.com/x?op=12&cou ...

  8. 第六节:用audio标签打造一个属于自己的HTML5音乐播放器

    上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...

  9. 开源html5在线音乐网站,一个漂亮的开源HTML5音乐播放器——APlayer

    介绍 APlayer是一个简约且漂亮的html5音乐播放器,支持多种模式,包括播放列表模式.吸底模式 .迷你模式.MSE模式.HLS模式. Github https://github.com/diyg ...

最新文章

  1. AI大牛周明打造的轻量“孟子模型”开源!靠10亿参数冲上CLUE榜第三,可用于新闻分类、文案生成...
  2. ABAP DOI详解(3)
  3. CCNP学习笔记2-路由部分--EIGRP
  4. CodeForces - 1360G A/B Matrix(最大流)
  5. /proc/net/sockstat 里的信息是什么意思?
  6. Nessus安全测试插件编写教程(2)
  7. zookeeper集群,每个服务器上的数据是相同的,每一个服务器均可以对外提供读和写的服务,这点和redis是相同的,即对客户端来讲每个服务器都是平等的。...
  8. 学习笔记12JS异步请求
  9. 如何在Git上创建工程,演示在Git中创建项目
  10. Android-Universal-Image-Loader学习笔记(4)--download
  11. vscode 左侧图标_分钟将vscode撸成小霸王
  12. 最简单AS5048a模块鉴别和读取数据
  13. 2021年房地产金融行业发展研究报告
  14. index函数python查询所有_Python List index()方法
  15. AppScan安全扫描工具-IBM Security App Scan Standard
  16. js的match 方法
  17. autojs-识图点击完整方法带源码及使用方法
  18. springboot热部署
  19. 2016.2.10-2.24 中关村图书大厦实习--图书管理系统;
  20. 二维码在ERP中的应用

热门文章

  1. 凭证录入模板-检查核算项目研发项目是否录入
  2. kubernetes Pod Lifecycle生命周期与livenessProbe、 readinessProbe探测方法
  3. 网红直播营销现状及对策研究
  4. 端到端的图像压缩----《Channel-wise Autoregressive Entropy Models For Learned Image Compression》论文笔记
  5. endnote没有加载项_word中手动添加endnote的加载项
  6. shell 脚本 基础
  7. 8 - 1 - Non-linear Hypotheses (10 min)
  8. 关于安卓 dp与px的理解
  9. c语言程序代码有什么用,用c语言编写的代码程序是什么?
  10. 微信小程序之植物识别demo(百度开发接口)