为 Hexo 博客添加文字荧光突出效果
本篇将以 Butterfly 主题为例,讲述如何为你的 Hexo 博客添加文字荧光突出效果。
文章包括了灵感以及探索的历程。如果不感兴趣可以直接在目录中跳转到「操作」。
效果
披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。
闾阎扑地,钟鸣鼎食之家;
舸舰迷津,青雀黄龙之舳。
云销雨霁,彩彻区明。
落霞与孤鹜齐飞,秋水共长天一色。
渔舟唱晚,响穷彭蠡之滨,
雁阵惊寒,声断衡阳之浦。
以上文字,出自 《滕王阁序》。
Markdown 源代码
1 | {% highlighter red %} |
灵感
周三那天,我看到了某位同学历史书上画的花里胡哨的荧光笔,又突然想旧技术博客的超链接也有类似效果;今天趁着假期,就翻出我自改的 fly-pro 主题的有关样式文件,发现有以下代码:
1 | a, |
渲染出就是一个荧光超链接的效果。
稍加改动,即可制作出 DEMO:
DEMO
1 |
|
遂欲用之于 Hexo 博客。乃制一标签外挂。
探索
段落
根据 Hexo 博客官方的文档《标签插件(Tag) | Hexo》,我们可以仿造一个 highlighter
标签(有结束标签),用于实现简单的效果。以 Butterfly 主题为例,可以这样添加自定义的标签外挂:
-
打开
[ThemeRoot]/scripts/tag
,新建一个highlighter.js
。不难写出:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* highlighter
* by PanDaoxi
*/
;
hexo.extend.tag.register(
"highlighter",
(args, content) => {
var color = args[0] + "-highlighter";
return `<span class="highlighter ${color}">${content}</span>`;
},
{ ends: true }
); -
打开
[ThemeRoot]/source/css
,新建样式文件custom.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
54
55
56
57
58
59.highlighter {
font-weight: bold;
}
.highlighter.red-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(215, 0, 58, 0.4) 0
);
}
.highlighter.orange-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(255, 165, 0, 0.4) 0
);
}
.highlighter.yellow-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(255, 255, 0, 0.4) 0
);
}
.highlighter.green-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(102, 204, 0, 0.4) 0
);
}
.highlighter.cyan-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(0, 255, 255, 0.4) 0
);
}
.highlighter.blue-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(0, 128, 255, 0.4) 0
);
}
.highlighter.purple-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(101, 125, 225, 0.4) 0
);
} -
打开样式配置文件(可以在
[ThemeRoot]/_config.yml
),找到inject
配置项。在head
添加:1
- <link rel="stylesheet" href="/css/custom.css"/>
-
重启博客。
1
2hexo cl
hexo s
这样即可配置好。
但是,渲染出的只是纯文字,不能使用 markdown 语法,甚至没办法换行。
接着,我们查阅文档《渲染 | Hexo》了解到可以通过以下代码渲染字符串为 html
:
1 | hexo.render.renderSync({ text: content, engine: "markdown", }); |
console.log
一下,七个标签分别得到的字符串是:
1 | <p>披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。</p> |
我们接下来就需要考虑如何给每个元素都添加上对应的类名。
考虑到字符串中可能存在多个 html 元素,就希望转化为 DOM
来处理。但是,在 Node.js 环境下使用 DOM
不可行,使用正则表达式匹配 html 元素标签不可靠。这时想到使用库 cheerio
。
安装 cheerio
:
1 | npm in cheerio |
highlighter.js
就需要写成:
1 | /** |
可惜还是不行。程序确实是为每个元素正确添加了类,但是却是操作了整个段落,即给 <p>
标签添加了 highlighter
类。这可不太美观。
于是又想到可以给有文字的部分包裹 <span>
标签,然后只给 <span>
标签添加类。
对于每一个元素,首先检查是否有非空白的文本内容;如果有,则遍历该元素的子节点,找到所有文本节点(node.nodeType === 3
),并对这些文本节点用一个 <span>
标签包裹,再添加相应类名。
现在 highlighter.js
这样写:
1 | /** |
也可以正确渲染了。
1 | <p> |
行内
众所周知,Butterfly 主题有丰富的标签外挂。在其文档《Butterfly 文檔(四) 標簽外挂 | Butterfly》中提到有一个
label
标签。效果如下:臣亮言:先帝创业未半,而中道崩殂。今天下三分,益州疲敝,此诚危急存亡之秋也!然侍卫之臣,不懈于内;忠志之士,忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气;不宜妄自菲薄,引喻失义,以塞忠谏之路也。
宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理;不宜偏私,使内外异法也。
它的原理很简单。在 [ThemeRoot]/scripts/tag/label.js
中体现了该标签的实现方法:
1 | /** |
根据刚才的经验,结合示例,我们可以写出:
1 | hexo.extend.tag.register( |
此时 {% ihighlighter 行内的 highlighter red %}
效果就是行内的 highlighter。只是你不能在行内标签使用 markdown 语句。
操作
-
在
[BlogRoot]
打开命令行(终端),输入以下命令:1
2
3npm in cheerio
// 如果有 cnpm 的话,也可以是
cnpm in cheerio -
打开
[ThemeRoot]/scripts/tag
,新建一个highlighter.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/**
* highlighter
* by PanDaoxi
*/
;
const cheerio = require("cheerio");
hexo.extend.tag.register(
"highlighter",
(args, content) => {
var color = (args[0] ? args[0] : "purple") + "-highlighter";
var html = hexo.render.renderSync({
text: content,
engine: "markdown",
});
const $ = cheerio.load(html);
$("body")
.find("*")
.addBack()
.each(function () {
if (
$(this)
.contents()
.filter(function () {
return this.nodeType === 3 && this.nodeValue.trim();
}).length
) {
$(this)
.contents()
.each(function () {
if (this.nodeType === 3 && this.nodeValue.trim()) {
$(this).wrap(
`<span class="highlighter ${color}"></span>`
);
}
});
}
});
return $("body").html();
},
{ ends: true }
);
hexo.extend.tag.register(
"ihighlighter",
(args) => {
var color = args[args.length - 1];
var text = args.slice(0, -1).join(" ");
// console.log(color, text);
return `<span class="highlighter ${color}-highlighter">${text}</span>`;
},
{ ends: false }
); -
打开
[ThemeRoot]/source/css
,新建样式文件custom.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
54
55
56
57
58
59.highlighter {
font-weight: bold;
}
.highlighter.red-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(215, 0, 58, 0.4) 0
);
}
.highlighter.orange-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(255, 165, 0, 0.4) 0
);
}
.highlighter.yellow-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(255, 255, 0, 0.4) 0
);
}
.highlighter.green-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(102, 204, 0, 0.4) 0
);
}
.highlighter.cyan-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(0, 255, 255, 0.4) 0
);
}
.highlighter.blue-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(0, 128, 255, 0.4) 0
);
}
.highlighter.purple-highlighter {
background: linear-gradient(
180deg,
transparent 70%,
rgba(101, 125, 225, 0.4) 0
);
}以上样式中共提供七种颜色
red
、orange
、yellow
、green
、cyan
、blue
、purple
。可自行添加。 -
打开样式配置文件(可以在
[ThemeRoot]/_config.yml
),找到inject
配置项。在head
添加:1
- <link rel="stylesheet" href="/css/custom.css"/>
-
重启博客。
1
2hexo cl
hexo s -
完成。