原生js html音乐播放器(歌词滚动)

本周学习了js的,用老师教的敲了一个音乐播放器

准备工作

首先随便找首歌
在这里插入图片描述
然后用一个小工具扒它的歌词

在这里插入图片描述
前期准备完成

代码部分

现在就开始写 htmlcss

很简单 就不解释了 直接上代码

html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Music player</title>
    <link rel="stylesheet" href="index.css" />
  </head>

  <body>
    <div class="container">
      <audio id="MusicPlayer" src="media/袁娅维 - Starfall.flac" controls loop></audio>
      <div class="btn">
        <button onclick="turn -= 0.1">-0.1s</button>
        <button onclick="turn += 0.1">+0.1s</button>
      </div>
      <div class="lrc">
        <ul id="ullrc">
         
        </ul>
      </div>
    </div>
    <script src="./index.js"></script>
  </body>
</html>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
*{
    box-sizing: border-box;
}
body{
    background: #000;
}
.container{
    width: 100%;
}
.container #MusicPlayer{
    width: 600px;
    display: block;
    margin: 0 auto;
}
.container .btn{
    display: block;
    margin: 0 auto;
}
.container .lrc{
    width: 700px;
    height: 450px;
    overflow: hidden;
    display: block;
    margin: 0 auto;
}
.container .lrc #ullrc{
    width: 100%;
    padding: 0;
    list-style: none;
    transition: 0.3s all ease;
    margin: 0;
}
/*歌词普通样式*/
.container .lrc #ullrc li{
    height: 35px;
    line-height: 35px;
    font-size: 1em;
    color: #aaa;
    font-weight: normal;
    transition: .3s all ease;/*一定要加上不然看着突兀*/
    list-style-type: none;
    text-align: center;
    display: block;
    width: 100%;
    margin: 0 auto;

}
/*动态歌词样式*/
.container .lrc #ullrc li.active{
    font-size: 1.2em;
    color: #fff;
    font-weight: bold;
}

js

完整js

先上完整js然后再讲一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
var lrc = ` 歌词
            歌词
            歌词`;

function $(id) {
    return document.getElementById(id);
}//这样写以后getid方便

function getLrcArray() {
    var parts = lrc.split("\n");
    for (let index = 0; index < parts.length; index++) {
        parts[index] = getLrcObj(parts[index]);
    }
    return parts;

    function getLrcObj(content) {
        var twoParts = content.split("]");
        var time = twoParts[0].substr(1);
        var timeParts = time.split(":");
        var seconds = +timeParts[1];
        var min = +timeParts[0];
        seconds = min * 60 + seconds;
        var words = twoParts[1];
        return{
            seconds: seconds,
            words: words,
        };
    }
}

var lrcArray = getLrcArray();

function inputLrc() {
    for (let index = 0; index < lrcArray.length; index++) {
        var li = document.createElement("li");
        li.innerText = lrcArray[index].words;
        $("ullrc").appendChild(li);
    }
}

inputLrc();

function setPosition() {
    var index = getLrcIndex();
    if (index == -1) {
        return;
    }
    var lrc_li_height = 35, lrc_ul_height = 450;
    var top = index * lrc_li_height + lrc_li_height / 2 - lrc_ul_height / 2;
    if (top < 0) {
        top = 0;
    }
    $("ullrc").style.marginTop = -top + "px";
    var activeLi = $("ullrc").querySelector(".active");
    if(activeLi){
        activeLi.classList.remove("active");
    }
    $("ullrc").children[index].classList.add("active");
}

var turn = 0;

function getLrcIndex(){
    var time = $("MusicPlayer").currentTime + turn;
    for (var index = 0; index < lrcArray.length; index++) {
        if (lrcArray[index].seconds > time) {
            return index - 1;
        }
    }
}

$("MusicPlayer").ontimeupdate = setPosition;

那接下来就到了我们的重头戏了

首先我们得到了歌词

但是是这样的

在这里插入图片描述

第一步 歌词信息获取

我们要从这样的字符串中得到信息,就需要先把每段分割开来

接着再从每一段去获取它的时间和歌词俩个信息

那就这样写

1
2
3
4
var lrc = `
这里是一大堆歌词
`;
var parts=lrc.split("\n");

这样就能把字符串根据回车分割开来,然后就是一步一步分割,直到达到我们要的格式

和上面一个逻辑就不解释了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function getLrcArray() {
    //分割每一列
    var parts = lrc.split("\n");
    //遍历分割每一句
    for (let index = 0; index < parts.length; index++) {
        parts[index] = getLrcObj(parts[index]);
    }
    return parts;

    function getLrcObj(content) {
        //把一句分割为俩部分
        var twoParts = content.split("]");
       
        var time = twoParts[0].substr(1);//将时间前的"["截掉
        var timeParts = time.split(":");//用秒处理比较翻版我们这里这里转换成秒
        var seconds = +timeParts[1];
        var min = +timeParts[0];
        seconds = min * 60 + seconds;
        //歌词获取
        var words = twoParts[1];
        return{//返回秒和歌词
            seconds: seconds,
            words: words,
        };
    }
}

var lrcArray = getLrcArray();//结果存储在这里

第二步 创建li

歌词文件都处理好了就没必要我们亲自去一个一个设置了,这里用js在页面上创建li元素

1
2
3
4
5
6
7
function inputLrc() {
    for (let index = 0; index < lrcArray.length; index++) {//不用数,有多少句创建多少li标签
        var li = document.createElement("li");
        li.innerText = lrcArray[index].words;//歌词放入
        $("ullrc").appendChild(li);//将这个li作为ul的子元素
    }
}

就没了

第三步 歌词位置滚动

这里歌词位置的滚动就是根据修改margin-top: ;进行的,然后给元素再增加一个active样式就可以了
但是margin-top: ;的值怎么确定呢?

在这里插入图片描述
我要让歌词居中显示,那么画一个模型出来是这样的

在这里插入图片描述
每次要让歌词的中间位置处于中线上,我们要算的其实就是溢出部分的高,将这个高写入 margin-top: -height;就可以实现效果了

那问题来了,这个溢出部分的高怎么算呢.我们假设现在播放到了第i行歌词,也就是说要处在中线上的歌词就是第i行歌词,
根据下图可知
溢出部分的高度就是 * i 歌词行高 + 行高 / 2 - 460 / 2*

(为了数组遍历,i是从0开始的)

在这里插入图片描述

接着就是写一个active样式,把选中的歌词加上样式,把其他的active去掉即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function setPosition() {
    var index = getLrcIndex();
    var lrc_li_height = 35, lrc_ul_height = 450;//定义行高和歌词box高度
    var top = index * lrc_li_height + lrc_li_height / 2 - lrc_ul_height / 2;//计算
    if (top < 0) {
        top = 0;//如果top为负说明歌词在开始几句,无需滚动,top归零
    }
    $("ullrc").style.marginTop = -top + "px";//改变mt
    var activeLi = $("ullrc").querySelector(".active");//寻找ul下类名为active的元素并返回之
    if(activeLi){
        activeLi.classList.remove("active");//删
    }
    $("ullrc").children[index].classList.add("active");//添
}

歌词行数获取

接着只要得到歌词在哪一行就可以了

这个很简单

比较播放时间,出现播放时间小于数组存的时间的情况,直接返回index-1

1
2
3
4
5
6
7
8
function getLrcIndex(){
    var time = $("MusicPlayer").currentTime;
    for (var index = 0; index < lrcArray.length; index++) {
        if (lrcArray[index].seconds > time) {
            return index - 1;
        }
    }
}

因为最开始时返回值为 -1,所以还要在前面的调用中判断如果 index == -1 的话退出函数