Markdown是一个轻量级的标记语言,同强大的HTML相比,它书写简单,冗余符号较少,易于学习。在保证最简单的语法的同时,对主流常用的文本格式均提供了支持。 我是从搭建这个博客时开始接触Markdown,至今已有一年有余。已经使用Markdown写了十几篇博文,爱不释手。 本文的内容主要是记录对由Markdown渲染出来的HTML进行后期处理的一些实践。更准确的来说,本文主要是对基于Github Pages的博文进行后期处理。

使用Markdown

  1. 首先,使用Markdown提供的标记书写出文章,一般Markdown文件的后缀名为.md或者.markdown
  2. 然后可以通过其它转换工具将Markdown文章渲染出来,或者转换成其它格式,如HTML,LaTex等。
  3. 如果生成的是HTML,再搭配一份CSS,就可以将文章渲染成一个优雅的页面。

Markdown存在着很多风格,不同的风格对标准Markdown语法的解释有些不一样。本文是基于Github风格的Markdown文本。 不同的转换工具也会提供对Markdown非语法层面的扩展,比如增加一些特定的tag来扩展新的格式。我提倡尽量减少对非语法层面扩展的依赖。也就是说尽量不使用这些转换器提供的tag,而是通过js脚本来实现扩展

结构

目录导航

Markdown中存在多级标题,我们可以为每一级标题生成一个目录,方便阅读的人快速定位感兴趣的内容。 Markdown中的标题对应于HTML中的<h1> - <h6>标签。假设我们要提取<h2>建立目录,基本思想就是利用js标本从文章开头,依次遍历每一个<h2>标签,提取标签内容,为标签设置id,然后将提取到的内容建立一个链接列表即可。 在我的博客中,我只对2级标题提取了目录,如果要对每一级都提取目录,可能要相对复杂一些,但是基本思想都是一样的。

// 添加一个返回顶部的按钮
$('body').attr('id','body-top');
var top = '<button type="button" class="btn btn-success" data="body-top">Top</button>';
$('#navbar-list').append(top);

// 遍历每一个 h2 标签
var counter = 0;
$('article').children('h2').each(function(index, elem){
	$(elem).attr('id', 'section-h2-' + counter);
    var btn = '<button type="button" class="btn btn-primary" data="' + $(elem).attr('id') + '">'+ $(elem).text() +'</button>';
    $('#navbar-list').append(btn);
    counter++;
});

// 设置点击动画
$('#navbar-list').children('button').each(function(index, elem){
    $(elem).click(function(){
        var id = $(elem).attr('data');
        var dst = $('#'+id).offset().top - $('.navbar-title').outerHeight(true) - 10;
        if(dst < 0)
        {
            dst = 0;
        }
        $("html,body").animate({scrollTop:dst},600);
    });
});

// navbar-list 为一个div,我使用了一个第三方的库stickUp
// 使其随滚动条移动
$('.navbar-title').stickUp();

渲染

代码着色

可以在两个阶段对代码进行着色:渲染时,渲染后。

  1. 渲染时着色 在使用Jekyll进行渲染时,可以使用Jekyll提供的标签{% highlight ruby %}{% endhighlight %} 代替 ```包裹代码块,为代码块设置语言,同时实现着色。 这种方法使用了非标准的Markdown标记,所以我没有采用这种办法。

  2. 渲染后着色 由```标注的代码块会生成 <pre> <code> 标签,因此可以使用js脚本,在浏览器本地进行着色。 我选择使用highlight.js库。highlight.js可以尝试识别代码所属的语言。但是识别效果不咋地。所以,我们还需要标注代码块所用的语言。 对于大部分文章,可以假设整篇文章中的代码都是采用同一种语言,因此,可以在文章的Front Matter中用一个变量保存当前文章的全局语言设置,然后在模板中引用该变量,保存到一个隐藏<input>标签中,最后通过js处理,将该隐藏<input>的值设置到每一个<pre><code>块中。

渲染后着色相关实现:

// front matter
---
layout: post
title:  "Verilog HDL语言要素 - 词法"
date:   2014-01-05 20:17:54
categories: Verilog
codelang: verilog
---
// post 模板
<input type="hidden" id="codelang" value="js" />
// js 脚本
// set code language, default cpp
var codelang = $('#codelang').attr("value");
if(codelang == "") codelang = "cpp";
$('pre code').each(function(index, elem){
    $(elem).attr("class", codelang);
});

// init & apply highlight
hljs.configure({
    tabReplace: '    ', // replace a tab with 4 spaces
})
hljs.initHighlighting();