美柑の部屋

涙は見せないと誓った。

Loading…

Octopress插件开发:点击展开与折叠

对于我的每一篇博文,一定存在那么一坨内容,有些人想去了解,而有些人不想去了解。如果这一坨内容直接显示在网页上,对于那些不想去了解的人未免是一种煎熬。在这种情况下,给读者一个可以将这些内容展开与折叠的按钮是再好不过的选择了。想了解的人,点击“展开”按钮再去阅读就可以;不想了解的人就不需要点击“展开”按钮,也不需要忍受这种煎熬了。这次我就开发了一个用来实现这种功能的插件。

之前我开发的几款插件都是Tag型插件,但是这次Tag型插件就不能实现我们想要的功能了。我们需要使用Block型插件(姑且命名为expand),将要显示的内容用{% expand title %}{% endexpand %}包裹起来。

Javascript部分

为了实现显示和隐藏效果,我用到了一些jQuery相关的函数。这些函数包括:
$(this).next():获取当前对象的下一个兄弟对象;
$(this).parent():获取当前对象的父级对象;
$(this).html():获取当前对象显示的内容;
$(this).html("text"):将当前对象显示的内容修改为text
$(this).toggle():切换当前对象的显示与隐藏状态(display属性);
$(this).click(function(){}):定义当前对象被点击时执行的函数。
有了上面这些内容作为基础,我们可以想象出对应的html代码的结构。首先加入一个按钮(假设该按钮拥有属性class="expandtitle"),然后在该按钮之后加入一个<div></div>块,二者位于同一层级。
我们可以在source/javascripts/octopress.js文件中找到$('document').ready(...)一行,加入下面的代码:

octopress.js
1
2
3
4
5
6
7
8
9
10
11
12
13
$('document').ready(function() {
    //该函数中已经有了一些内容,不用管它,直接在这些内容后面添加。

    //Expand:
    $(".expandtitle").click(function(){
        $(this).next().slideToggle();
        var content = $(this).html();
        if(content == "展开")
            $(this).html("隐藏");
        else
            $(this).html("展开");
    });
});

这段代码指的是对所有class="expandtitle"的对象,添加一个点击时触发的函数:该函数切换了当前对象下一个兄弟对象的显示与隐藏状态,并且修改了当前对象对应的html文本。

插件实现部分

在插件目录下新建expand.rb,之前已经说过了,我们新建的类需要继承自Liquid::Block。我参照了blockquote插件的实现方法,首先在initialize函数中通过变量markup获取title部分,然后在render函数中通过调用super获得已经解析好的content部分,最后将两部分整合到一段html代码中。完整的代码如下:

expand.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module Jekyll
    class Expand < Liquid::Block
        def initialize(tag_name, markup, tokens)
            str = "#{markup}".strip
            @title = str
            super
        end

        def render(context)
            "<div class=\"expand\">#{@title}<a href=\"javascript:void(0)\" style=\"float: right;\" class=\"expandtitle\">展开</a><div class=\"expandcontent\" style=\"display: none;\">#{super}</div></div>"
        end
    end
end

Liquid::Template.register_tag('expand', Jekyll::Expand)

在对应的html代码中,我用<a></a>表示按钮,该按钮拥有如下属性:
href="javascript:void(0)":这其实是一个死链接,不指向任何地方。其实不加这句话,代码也可以正常工作,但是鼠标移到该按钮上不会显示出手形。给该按钮添加一个超链接,可以让鼠标移动到上面的时候显示出手形,更加符合用户的习惯。
style="float: right;":这段代码使得该按钮一直位于一行的最右侧。
class="expandtitle":对应我们在source/javascripts/octopress.js文件中增加的代码,使该按钮在点击时触发效果。

按钮的下一个兄弟对象则是需要隐藏或展开的部分,我用<div></div>表示,并且该元素的属性style="display: none;"保证其初始状态是隐藏的。

样式表调节部分

照例,样式表调节的部分仍在_styles.scss文件中完成,每个人可以根据自己的喜好定义.expand.expandcontent的样式。我定义的样式如下:

定制.expand.expandcontent的样式展开

有些人可能想将一段行内代码或整个代码段隐藏起来,这当然是可以的,但是它们显示的外观可能并不令人满意。我们可以在_styles.scss文件中,定制div.expand类型元素或.expandcontent类型元素中的行内代码或代码段的样式表:

定制行内代码或代码段的样式展开

局限性

插件的基本开发过程大致就是这样,就像上面所说的,该插件支持将一些内容折叠起来。可折叠的内容包括一段文本、一张图片或者一段代码段(因为Octopress支持插件嵌套)。但是该插件有一点局限性存在:在该插件内部,除去用{% plugin_name parameters %}调用插件的语法之外,其余的markdown语法(包括用两个空格换行,或者用三个反引号引用一段代码段)都不适用了。在这里,我提供了几种方案来解决上面的问题:
1. 要在本插件内部换行,直接写<br/>吧;
2. 要在本插件内部添加代码段,不要用三个反引号,改用codeblock吧;
3. 要在本插件内部添加行内代码,不要用反引号,直接写成<code>...</code>吧,或者把下面的code.rb文件加入到插件目录下后,用{% code ... %}吧。

code.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module Jekyll
    class CodeTag < Liquid::Tag
        def initialize(tag_name, markup, tokens)
            @code = "#{markup}".strip
            super
        end

        def render(context)
            "<code>#{@code}</code>"
        end
    end
end

Liquid::Template.register_tag('code', Jekyll::CodeTag)

评论