# jquery-mobile-player **Repository Path**: alex1504/jquery-mobile-player ## Basic Information - **Project Name**: jquery-mobile-player - **Description**: 基于jQuery的HTML5移动端音乐播放器 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: https://github.com/alex1504/jquery-mobile-player - **GVP Project**: No ## Statistics - **Stars**: 8 - **Forks**: 2 - **Created**: 2017-11-09 - **Last Updated**: 2022-05-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 项目说明  项目完成于2016年,那时候刚刚了解前端,jQuery似乎是成为了必会的工具,为了提升实战能力于是做了此案例,由于项目包含的MP3文件较大,github仓库移除了res文件夹,完整项目文件见[码云仓库地址](https://gitee.com/alex1504/jquery-mobile-player),希望该教程对新人有所启发。 预览地址:请猛击[这里](http://alex1504.gitee.io/jquery-mobile-player) 注意:使用PC浏览最好打开**移动设备模式**,使用移动设备浏览需要关闭无痕浏览模式(否则无法使用本地存储,一般浏览器都是默认不开启),项目需要在**本地服务器**或**线上服务器**运行,以file:///形式的地址打开是无法进行ajax请求的,从而无法看到音乐数据。 # 项目实现的功能及所用知识 # - 播放器的基础操作,上一首,下一首(顺序播放、随机播放、单曲循环),播放暂停,滑动时间轴的歌词定位 - 初始handlebar模板渲染音乐列表数据,下拉滚动加载音乐列表数据。 - 歌曲列表可添加喜爱音乐,于下次刷新时更新喜爱音乐列表,基于HTML5本地存储。 - 布局采用rem布局,自适应移动端手机设备。 - iconfont在线图标应用的使用 # 项目目录文件结构 # - css:存放样式文件 - lib: 存放公共脚本库 - js: 存放项目脚本文件 - img: 存放图片 - fonts: 项目字体文件 - res: 项目音乐资源 - ui:项目ui文件(psd) # 项目js文件结构 # ```javascript // ============================配置变量================================ 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。 ```html ``` **js:** ```javascript 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 += "
标签的高度将为0,这会影响歌词向上移动距离的不统一。因此下面作出个判断如果为空,则替换为“--------------”。(为空的时候大多数是歌曲中间停顿或过渡的时候) ```javascript function renderLyric(songinfo) { var arrMap = Util.createArrMap(songinfo.lyric); var tpl = ""; $.each(arrMap.lyricArr, function(index, lyric) { var lyricContent = lyric === "" ? "--------------" : lyric; tpl += "
" + lyricContent + "
"; }); Dom.lrcwrap.html(tpl); } ``` ### 歌词同步 ### 歌词同步我写在了syncLyric方法中,监听audio元素的timeupdate事件调用。 这个方法接收两个参数,第一个是当前播放歌曲时间(秒),第二个是转化为秒数的时间点数组。 如果当前时间>=时间点,那么高亮当前歌词(以lrcHighIndex)存储,并且lrcHighIndex自增1。 当歌词高亮索引lrcHighIndex>=1即歌词高亮不为第一句时,计算索引并让歌词盒子向上移动。 ```javascript 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++; } } ``` # 后记(于2017-11-9) 时隔两年,回顾当年所走的路,不仅感概前端的变化远快于自己的成长速度,不过庆幸的是自己并没有选错这条路,因为我发现开发不仅已经成为了自己的工作,更是融入了自己的生活,成为生活的一部分;其次,这是开发者最好的时代,我不仅能从互联网挖掘我所有想要深入的知识,也感受者开源社区带给我的魅力,希望自己能从知识的接收者变成知识的传播者,与您共勉。