专栏首页KrryblogLily_music 网页音乐播放器 -可搜索(附歌词联动播放效果解说)
原创

Lily_music 网页音乐播放器 -可搜索(附歌词联动播放效果解说)

博客地址:https://ainyi.com/59

写在前面

这是我今年(2018)年初的小项目,当时也是手贱,不想用别的播放器,想着做一个自己的网页播放器,有个歌曲列表、可关键词搜索、歌词滚动播放的效果,于是乎,就做了这一个 Lily_music

当时的感慨

有好几天没有发表博客了,这也是因为一直开发音乐和完善我的博客项目,好不容易抽出时间总结一下这几天所做的东西,还这么多课,实则匆忙

今天难得逃了一次课,就趁这时间,该写写就写写吧~~

进入正题:Lily_music

本次开发,参照本人之前所做的 乐诗博客(文末会说到)的相关播放控制等功能,继续优化的结果

前端模仿qq音乐界面,然后在此之上进行修改的界面,并使用了一点 es6 的语法

话说个人挺喜欢qq音乐界面的,简洁,当然也少不了背景模糊插件以及滚动条美化相关插件

也用到了弹窗、点击复制歌曲链接和歌词链接相关功能,但是目前歌曲分享功能暂未实现、后续....

==致谢==:歌曲搜索参照某位大佬封装的 qq 音乐的 api,UI 界面参照另一位大神的一些解决方案,在此表示感谢

相关插件

那么相关使用的开源插件有:

  1. jQuery 官方类库:https://jquery.com
  2. layer 弹窗插件:http://layer.layui.com
  3. 复制粘贴库插件:https://www.npmjs.com/package/clipboard-js
  4. mCustomScrollbar 滚动条美化插件:http://manos.malihu.gr/jquery-custom-content-scroller
  5. background-blur 背景图片模糊特效插件:https://msurguy.github.io/background-blur

还有播放、控制、歌词解析、搜索、加载动画sg类库等功能全部手写,爽的不行

温馨提醒

本播放器并不需要什么特别的运行环境,直接下载打开就能用了 ^_^

响应式优化,可在各种大小的设备运行打开

音乐搜索的结果均来自 qq音乐 (后续会继续扩大到多个平台)

本播放器还有一些 bug,需求就是不断满足的,虚心请教...

谈谈开发

果断使用的是 H5 播放器,十分好用

一般在做这种播放器的开发,要多多使用面向对象的开发思想

定义一个播放器对象,相关参数、方法如下:

播放器对象:krAudio

参数:

  播放器:audioDom

  进度条锁定:locked:true

  进度条按下的锁:kdown

  静音的锁:flag_volume

  当前音量:curentVoice

  当前播放的列表序号:Currentplay

  当前播放列表歌曲总数:allItem

  播放模式,1 为列表循环:orderModes

方法:

  播放器初始化:init

  设置播放的音乐地址:seturl

  播放:play

  暂停:stop

  播放时间监听及处理:time

  时间格式化:format

  下一首:next

  上一首:prev

  播放模式:ordermode

  拖动进度条:controlTime

  拖动音量条:controlVoice

上面部分的参数及方法基本涵盖播放器该有的功能,定义好了整个播放器对象所需要的参数和方法,就可以进行具体开发了

歌词联动播放

具体谈谈这个功能的实现

歌词解析,我之前做的==乐诗博客==采用的是自己写的一种歌词解析滚动播放的方法

首先明白一般歌词的形式是:

00:13.80期望飞上恬静月球遥望每家的窗

00:18.24谁伴深爱细味露台玫瑰香

这样子的形式,利用 ajax 异步请求到歌词文件内容,然后就可以进行字符串裁剪,单单取出时间和歌词,html5 播放器可以获取到当前播放时间,就可以实现==当前播放时间==和==当前歌词==一一对应,附上代码:

loadLrc :function(){//加载歌词
  var vallrc = $(".hidetextlrc").text();
  //如果没有上传歌词或者删除了歌词
  if(!vallrc || $(".is_deleteLrc").text() == 1){
    $(".lrc_content_notext").text("暂无歌词");
    $(".lrc_content_notext").show();
    return;
  }
  var isHrefLrc = $(".is_href_lrc").text();
  //如果是上传的歌词,那就要拼接上服务器地址
  if(isHrefLrc == 0) vallrc = basePath + "/" + vallrc;
  $.ajax({  //异步请求获取本地歌词
    url:vallrc,
    type:"post",
    success:function(data){
      //第一次分离歌词
      var lrcArr = data.split("[");
      //存放分离后的歌词
      var html = "";
      var lrclast = null; //记录上一行的歌词
      var lrcmes = null; //记录当前行的歌词
      var bofo = -1; //记录上一行歌词的秒数
      var ms = -1; //当前这一行的秒数
      for(var i = 0;i < lrcArr.length;i++){
        //第二次分割歌词,变成["03:01.08","这个世界变得更加美丽"],数组以逗号分隔
        var arr = lrcArr[i].split("]");
        //取到数组arr下标为1的歌词部分
        //将上一行的歌词赋值给lrclast
        lrclast = lrcmes; 
        //得到当前歌词
        lrcmes = arr[1];
       //取到时间
        var time = arr[0].split("."); //变成["03:01","08"]
        //取到time下标为0的分钟和秒
        var ctime = time[0].split(":"); //变成["03","01"];
        //将上一行的秒数赋值给bofo
        bofo = ms;
        //转化成秒数
        ms = ctime[0]*60 + ctime[1]*1;
        //如果上一行和当前行秒数相同,则当前行秒数++ ,解决秒数相同的办法
        if(bofo == ms){
          ms++;
        } else if (ms >= 0){
          if(!isNaN(bofo)){ // 如果是数字
            var classeName = "l_"+bofo;
            var concon = bofo; // bofo会自增,所以下面for循环条件用这个变量来代替
            for(var j = 0;j < ms-concon-1;j++){
              classeName += " l_"+ ++bofo;
            }
            if(ms>=0 && lrclast != null){
              html += "<li class='"+classeName+"'>"+lrclast+"</li>";
            }
          }
        }
      }
      //装载最后一行歌词的机制,先获取歌曲总时间
      setTimeout(function(){
        var allall = krAudio.audioDom.duration;
        var classlaName = "l_"+ms;
        var conben = ms; //ms会自增,所以下面for循环条件必须用这个变量来代替
        for(var j = 0;j < allall-conben-1;j++){
          classlaName += " l_"+ ++ms;
        }
        html += "<li class='"+classlaName+"'>"+lrcmes+"</li>";
        //把解析好的歌词放入歌词展示区中
        $("#lrcly").html(html);
        $("#lyrics").html(html);
      },200);
    }
  });
  // 联动音乐播放歌词
  krAudio.audioDom.addEventListener("timeupdate",function(){
    //获取当前播放时间,获得的是秒数
    var time = this.currentTime;
    //解析音乐对应的时间
    var m = parseInt(time / 60);//获取此时的分钟
    var s = parseInt(time); //转换int类型,获取此时的秒数
    $(".l_"+s).addClass("lrcsel").siblings().removeClass("lrcsel");
    //歌词滚动条,使歌词在中间的计算公式:
    //第n行歌词*li的高度-歌词区域中间的li(就是包括这个li,取这个li的一半)以上的li的总高度
    //局部歌词的控制
    $(".lrc_content_box").stop().animate({
      scrollTop:(($(".lrcsel").index()+1)*29 - 145)//减去偏差,使当前歌词在中间
    },240);
    //全屏歌词的控制
    $("#lyrics").stop().animate({
      scrollTop:(($(".lrcsel").index()+1)*24 - 168)//减去偏差,使当前歌词在中间
    },240);
  });
},

这种==歌词解析==、==联动播放==的实现是我之前==乐诗博客==采用的一种方案,感觉也不错

重点来了

此次采用的是另一种歌词解析方式,利用 js 正则表达式全部替换的方式

替换方式

var reg = /-/g;  // g表示全部替换 ,要替换的字符串是-
createTime = createTime.replace(reg,"/"); // 第二个参数表示替换成 /
 // 替换成2018/04/03 歌词解析//解析歌词
function parseLyric(lrc) {
 var lyrics = lrc.split("\n");
 var lrcText = {};
 for(var i=0;i<lyrics.length;i++){
   var lyric = decodeURIComponent(lyrics[i]);
   var timeReg = /\[\d*:\d*((\.|\:)\d*)*\]/g;
   var timeRegExpArr = lyric.match(timeReg);
   if(!timeRegExpArr)continue;
   var clause = lyric.replace(timeReg,'');
   for(var k = 0,h = timeRegExpArr.length;k < h;k++) {
     var t = timeRegExpArr[k];
     var min = Number(String(t.match(/\[\d*/i)).slice(1)),
     sec = Number(String(t.match(/\:\d*/i)).slice(1));
     var time = min * 60 + sec;
     lrcText[time] = clause;
   }
 }
 return lrcText;
}

这样子解析出来的是一个对象,存放着键值对

键:==时间(秒)==

值:==歌词==

就可以直接做一个 for in 循环将每句歌词添加到歌词区域,将时间添加到每句歌词的样式控制 class 名

根据每句歌词的时间,就可以在播放器的 timeupdate 监听事件里实现滚动播放歌词了(代码上面有)

拖动进度条

鼠标拖动进度条的时候,有三个监听事件

按下:onmousedown

移动:onmousemove

弹起:onmouseup

这里鼠标移动事件需要放在鼠标按下事件里面,当鼠标弹起时,在里面清除移动、弹起两个事件,以免弹起时还执行鼠标按下拖动事件(也可以定义一把锁来控制)

还有很多细节点的问题,上一曲下一曲临界值、搜索后的播放控制、列表小菜单与主按钮之间的联动、三种播放模式(顺序播放、随机播放、单曲循环)等等等等... 有坑也有欢笑

截图展示

项目链接

在线演示:Lily_music

Github:https://github.com/Krryxa/Lily_music

欢迎 Start

博客地址:https://ainyi.com/59

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自制 h5 音乐播放器 可搜索

    有好几天没有发表博客了,这也是因为一直开发音乐和完善我的博客项目,好不容易抽出时间总结一下这几天所做的东西,还这么多课,实则匆忙

    Krry
  • 分享:纯 css 瀑布流 和 js 瀑布流

    通过 Multi-columns 相关的属性 column-count、column-gap 配合 break-inside 来实现瀑布流布局。

    Krry
  • flex 布局

    CSS3 为我们提供了一种可伸缩的灵活的 web 页面布局方式 flexbox 布局,它具有很强大的功能,可以很轻松实现很多复杂布局。可以简便、完整、响应式地实...

    Krry
  • 自制 h5 音乐播放器 可搜索

    有好几天没有发表博客了,这也是因为一直开发音乐和完善我的博客项目,好不容易抽出时间总结一下这几天所做的东西,还这么多课,实则匆忙

    Krry
  • JS魔法堂:ASI(自动分号插入机制)和前置分号

    一、前言                                   今晚在知乎看到前端技术专家——贺师俊对《JavaScript 语句后应该加分号么?...

    ^_^肥仔John
  • 快速入门系列--WCF--01基础概念

    转眼微软的WCF已走过十个年头,它是微软通信框架的集大成者,将之前微软所有的通信框架进行了整合,提供了统一的应用方式。记得从自己最开始做MFC时,就使用过Nam...

    用户1216676
  • fullcalendar日历插件的使用并实现增删改查

    我上个项目是做了一个关于教育方面的web端页面,其中的课程表就要用到fullcalendar日历插件,刚开始也是不会用,因为以前也没用过,后面也是看官方文档,问...

    故久
  • 前端知识小结

    1. var a=null==undefined?1:"abc"; var b=typeof(a); var c=typeof(b); var d=typeof...

    八哥
  • 跨行零基础转行前端,到底需要学多少东西才够用?

    现在新进入前端的人主要分二类,一是毕业就学前端的;二是做了几年其它工作,然后转行前端开发。从大的就业效果上来看,工作几年之后再跨行的人,就业率要明显低于前者。 ...

    web前端教室
  • Redis之MISCONF Redis is configured to save RDB snapshots错误

    操作redis过程中并没有修改什么配置,出现如下错误, Redis之MISCONF Redis is configured to save RDB snap...

    学到老

扫码关注云+社区

领取腾讯云代金券