美柑の部屋

涙は見せないと誓った。

Loading…

在自己的博客中加入歌词栏

很久之前我就有将自己喜欢的歌曲分享给别人的梦想,而现在正值我的博客搭建完成,我终于可以通过在博客中加入歌词栏实现我的梦想了。这篇文章就来简单介绍一下在博客中添加歌词栏的流程。

一、添加html文件

首先,在source/_includes/custom/路径下新建lyrics.html文件,我们要添加的歌词栏就是在该文件中实现的。该文件的内容暂且按下不表,我们首先要让我们添加的html文件在博客中显示出来。
我们知道,source/_layouts/default.html文件定义了博客页面的基本框架,当我们需要添加一些内容的时候,可以修改该文件,这样在博客的任何页面,我们添加的内容都可以显示出来。如大家所见,本博客中歌词栏的位置位于导航栏的下面,正文部分的上面。通过查看default.html文件,我们发现,{% include navigation.html %} 一行对应着博客的导航栏,而我们要加入的lyrics.html,则应该放在这一行的下面。
在这一行的下面加入{% include custom/lyrics.html %}一行,这样一来,我们添加的歌词栏就在博客页面中找到了自己的归属。

二、歌词栏的实现

关于歌词栏,我的想法是这样的:中间部分显示歌词,包括日文原文、中文译文以及歌曲名称和歌手名称,其中歌曲名称是一个超链接,指向网易云音乐中对应歌曲的页面。两侧分别是两个按钮,即切换到上一句歌词和下一句歌词。
我在source/文件夹下新建了lyrics/文件夹,歌词栏显示的每句歌词都对应着该文件夹下的一个txt文件,文件名形如1.txt2.txt这样。除了这些歌词文件,该文件夹下还有一个num.txt文件,记录着当前歌词的总数量。在博客页面第一次加载的时候,首先访问num.txt文件,获取歌词总数量totNumber,然后随机生成一个介于1totNumber之间的数字curNumber,并且访问[curNumber].txt文件,将该文件对应的歌词显示在歌词栏中。每当点击上一句歌词或下一句歌词按钮时,将curNumber减一或加一,并且访问对应的文件并且更新歌词栏的信息。
那么问题来了:如何访问服务器端的一个文件呢?我们需要用到XMLHttpRequest。通过XMLHttpRequest,我们可以实现很多功能,比如:
1. 在不重新加载页面的情况下更新网页;
2. 在页面已加载后从服务器请求数据;
3. 在页面已加载后从服务器接收数据;
4. 在后台向服务器发送数据。
而我们则是利用了第二点“在页面已加载后从服务器请求数据”的功能。相关代码如下:

XMLHttpRequest的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function loadXMLDoc(url){
    xmlhttp = null;
    if(window.XMLHttpRequest){ // code for Firefox, Opera, IE7, etc.
        xmlhttp = new XMLHttpRequest();
    }else if (window.ActiveXObject){ // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (xmlhttp != null){
        xmlhttp.onreadystatechange = state_change;
        xmlhttp.open("GET", url, true);
        xmlhttp.send(null);
    }
}

function state_change(){
    if(xmlhttp.readyState == 4){ // 4="loaded"
        if (xmlhttp.status == 200){ // 200="OK"
            var text = xmlhttp.responseText;
        }
    }
}

在上述代码中,onreadystatechange是一个事件句柄,它的值是一个函数名称。当我们建立的XMLHttpRequest对象的状态发生改变后,会触发此函数。该对象的状态从0到4进行变化,其中状态为4意味着请求完成,然后我们才可以进行后续处理。
在该对象状态发生改变后,如果是请求完成状态,我们就可以通过该对象的status属性判断我们的请求是否成功。status属性对应着该请求的http状态代码,如果成功,状态代码即为200。如果成功,我们即可通过responseText属性获得我们请求的内容。
明确了XMLHttpRequest的作用,完整的html代码也就呼之欲出:

lyrics.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
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
73
74
75
76
77
78
<div id="lyrics">
    <a id="leftArrow" onclick="last();" href="javascript:void(0)"></a>
    <a id="rightArrow" onclick="next();" href="javascript:void(0)"></a>
    <script type="text/javascript">
        var xmlhttp;
        var totNumber = -1;
        var curNumber;

        function getLRCNum(){
            loadXMLDoc("/lyrics/num.txt");
        }

        function adjustPos(){
            var pos = $("#lyrics").height() / 2 - 45;
            $("#leftArrow").css("margin-top", pos);
            $("#rightArrow").css("margin-top", pos);
        }

        function last(){
            curNumber--;
            if(curNumber <= 0)
                curNumber = totNumber;
            loadXMLDoc("/lyrics/" + curNumber + ".txt");
        }

        function next(){
            curNumber++;
            if(curNumber > totNumber)
                curNumber = 1;
            loadXMLDoc("/lyrics/" + curNumber + ".txt");
        }

        function loadXMLDoc(url){
            xmlhttp = null;
            if(window.XMLHttpRequest){ // code for Firefox, Opera, IE7, etc.
                xmlhttp = new XMLHttpRequest();
            }else if (window.ActiveXObject){ // code for IE6, IE5
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            if (xmlhttp != null){
                xmlhttp.onreadystatechange = state_change;
                xmlhttp.open("GET", url, true);
                xmlhttp.send(null);
            }
        }

        function state_change(){
            if(xmlhttp.readyState == 4){ // 4="loaded"
                if (xmlhttp.status == 200){ // 200="OK"
                    //处理传回的数据:
                    var text = xmlhttp.responseText;
                    if(totNumber < 0){ //如果是获取歌词数量;
                        totNumber = parseInt(text);
                        curNumber = Math.floor(Math.random() * totNumber) + 1;
                        loadXMLDoc("/lyrics/" + curNumber + ".txt");
                    }else{
                        var splited = text.split("\n");
                        $("#lyric").html(splited[0]);
                        $("#translate").html(splited[1]);
                        $("#singer").html("————" + splited[2]);
                        $("#song").html("「" + splited[3] + "」");
                        $("#song").attr("href", splited[4]);

                        //调节两个按钮的位置:
                        $("#leftArrow").show();
                        $("#rightArrow").show();
                        adjustPos();
                    }
                }
            }
        }
    </script>
    <div id="lyricsContent"">
        <h3 id="lyric"></h3>
        <p id="translate"></p>
        <p id="from"><span id="singer"></span><a id="song" href="javascript:void(0)"></a></p>
    </div>
</div>

我们注意到,getLRCNum()函数是用来获取歌词总数量的,需要在文档加载完成时调用。source/javascripts/octopress.js文件中的$('document').ready(function())函数是用来定义文档加载完成时所触发的函数的,我们需要在该函数的末尾调用getLRCNum()函数,确保在文档加载完成时,可以立刻获取当前歌词的总数量。
然后,last()next()函数则是分别在两个按钮被按下时触发的,它们更改了curNumber的值,并且请求了新的歌词内容。在新的歌词内容请求完成后,我们利用jQuery动态地改变了歌词栏内部的一些html标签所显示的文本及其href属性,并且通过adjustPos()函数调节了两个按钮的位置,使其在垂直方向上一直处于正中央。

三、定制css样式表

当然,为了显示出正常的效果,我们需要对html文件中涉及到的标签定制css样式表。这些工作仍然是在sass/custom/_styles.scss文件中完成的。由于笔者不是学美工出身,最后显示的效果或多或少会缺乏美感,这里贴出我个人定制的样式表,仅供抛砖引玉之用。

我个人定制的样式表展开

四、总结与展望

本文简单介绍了我为博客添加歌词栏的流程。在歌词栏添加好后,如果要添加新的歌词,只需要改动两处:一是更新source/lyrics/num.txt中记录的歌词总数;二是在source/lyrics/目录下建立一个新的文件保存要添加的歌词。已经写好的html代码和javascript代码均不需改动。这样的歌词栏已经大致满足了我的要求,但是必须承认,它还有一些可以改进的地方,在这里列出三点:
1. 不需要利用一个额外的文件num.txt来存储歌词总数,而是直接通过文件夹下的文件数量获得歌词总数。我相信肯定有相关的API可供调用,但是到目前为止还仍未找到。
2. 完善多分辨率支持,使得歌词栏在电脑、平板和手机上都可以正常显示。
3. 改进css样式表,使得歌词栏的外观更加漂亮。

评论