使用Chirpy主题发表文章时,插入的代码块会全部显示出来。在代码行数比较多的情况下,读者的阅读体验会比较差。阿猪希望能实现CSDN博客那样的折叠展示效果。
  经过一番折腾,终于搞定。先上效果图:

一、代码原型

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
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>折叠代码块示例 - Demo of fold code blocks</title>
<style>
.collapsible-container {
margin-bottom: 10px;
}

.collapsible-container p {
cursor: pointer;
margin: 0;
}

.collapsible-content {
overflow-x: auto;
overflow-y: hidden;
margin-top: 10px;
max-height: calc(1.5em * 5); /* 折叠时的默认高度 Default fold height*/
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
let coll = document.getElementsByClassName("collapsible-container");
let maxLines = 5; // 设置折叠显示的行数 Maximum number of lines to display without collapsing

for (let i = 0; i < coll.length; i++) {
let trigger = coll[i].querySelector('.collapsible-trigger');
let content = coll[i].querySelector('.collapsible-content');
let codeLines = content.textContent.split('\n').length;

/*codeLines=实际行的行数*2+一行换行空行,因为chirpy主题使用了<table>标签,里边包含两列,所以js会将1行代码视为2行。下边被注释掉的代码可以查看codeLines的真实值。codeLines=real_lines*2+1wrap_blank_line,because the chirpy theme uses <table> with 2 columns,which js reguard 1 line as 2 lines. The code section below can help you see the real value of codeLines.*/
let tempcodeLines = content.textContent.split('\n').length;
let lineCount = document.createElement('span');
lineCount.textContent = ' (' + tempcodeLines + ' lines)';
coll[i].appendChild(lineCount);

if (codeLines -3 <= maxLines) {
trigger.style.display = 'none';
} else {
trigger.addEventListener("click", function () {
this.classList.toggle("active");
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
}
});
</script>
</head>
<body>
<p>折叠代码块示例 - Demo of fold code blocks</p>

<div class="collapsible-container">
<pre class="collapsible-content">
<code>
function helloWorld() {
console.log("Hello, World!");
}
function helloWorld() {
console.log("Hello, World!");
</code>
</pre>
<p class="language-javascript collapsible-trigger">展开/收起 - Fold/Unfold</p>
</div>
</body>
</html>

  在上边的代码中:
(1)根据代码的结构,选择一个合适的标签位置作为容器,为其添加collapsible-container类属性。建议使用collapsible-content的父级容器。这里使用了<pre>的父级容器<div>
(2)根据代码的结构,在collapsible-container的内部选择一个合适的标签作为折叠/展开的对象,为其添加collapsible-content类属性。这里使用了用作格式预处理的<pre>标签,因为它完整的包含了用于展示的代码内容。
(3)根据代码的结构,在collapsible-container的内部、collapsible-content之外,选择一个合适的标签放置点击动作。这里选择在</pre>的下方放置一个<p></p>
(4)<style>内部通过CSS控制折叠时的高度等显示效果。
(5)<script>内部通过JavaScript实现折叠/展开的动作。

二、修改Chirpy主题

  根据Chirpy主题的代码结构特征,阿猪的大致修改思路是:
(1)选择<div class="language-xxx highlighter-rouge">作为容器;
(2)选择<div class="highlight">作为折叠/展开的对象;
(3)在<div class="highlight"></div>的后边插入点击按钮;
(4)将JavaScript语句存放为单独的外部文件,在<div class="post-content">的前边插入引用语句;
(5)将CSS插入现有的css文件中。

  请谨慎修改,注意Chirpy主题的版本差异可能会导致行位置不同或代码结构不同。具体的修改过程如下,仅供参考:

1、修改"\_includes\refactor-content.html"

(1)第29行,在第2个<div>的class中增加一个collapsible-content
(2)第198行,在<div>的class中增加一个collapsible-content
(3)第199行,在<div>的class中增加一个collapsible-content
(4)第230行,在<div>的class中增加一个collapsible-content
(5)第30行,在</code></div>之后添加入下代码:

1
<p class="language-javascript collapsible-trigger collapsible-trigger-css">展开/收起</p>

(6)第26行,插入如下代码:

1
2
3
4
5
{% if _content contains '<div class="language-' and '<div class="post-content">'%}
{% assign _content = _content
| replace: '<div class="language-', '<div class="collapsible-container language-'
| replace: '<div class="post-content">', '<script src="/assets/js/collapsible.js"></script><div class="post-content">' %}
{% endif %}

2、修改\assets\css\style.scss

  在文件的最下方空白处插入如下代码:

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
.collapsible-container {
margin-bottom: 10px;
}

.collapsible-container p {
cursor: pointer;
margin: 0;
}

.collapsible-content {
overflow-x: auto;
overflow-y: hidden;
margin-top: 10px;
max-height: calc(1.6em * 5); /* Adjust this value to show more lines (n) */
}
.collapsible-trigger-css {
color: gray;
text-align: center;
font-size: small;
}

/* 为代码展示框设置滚动条样式,仅针对WebKit浏览器 */
.collapsible-content::-webkit-scrollbar {
width: 8px; /* 滚动条宽度 */
height: 8px; /* 滚动条高度(对于水平滚动条) */
}

.collapsible-content::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2); /* 滚动条滑块颜色 */
border-radius: 6px; /* 滚动条滑块圆角 */
}

.collapsible-content::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.3); /* 滚动条滑块鼠标悬停颜色 */
}

.collapsible-content::-webkit-scrollbar-track {
background-color: #f1f1f1; /* 滚动条轨道颜色 */
border-radius: 6px; /* 滚动条轨道圆角 */
}

3、创建\assets\js\collapsible.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
document.addEventListener("DOMContentLoaded", function () {
let coll = document.getElementsByClassName("collapsible-container");
let maxLines = 5; // 设置折叠显示的行数 Maximum number of lines to display without collapsing

for (let i = 0; i < coll.length; i++) {
let trigger = coll[i].querySelector('.collapsible-trigger');
let content = coll[i].querySelector('.collapsible-content');
let codeLines = content.textContent.split('\n').length;

/* codeLines=实际行的行数*2+一行换行空行,因为chirpy主题使用了<table>标签,里边包含两列,所以js会将1行代码视为2行。下边被注释掉的代码可以查看codeLines的真实值。codeLines=real_lines*2+1wrap_blank_line,because the chirpy theme uses <table> with 2 columns,which js reguard 1 line as 2 lines. The code section below can help you see the real value of codeLines.
let tempcodeLines = content.textContent.split('\n').length;
let lineCount = document.createElement('span');
lineCount.textContent = ' (' + tempcodeLines + ' lines)';
coll[i].appendChild(lineCount);
*/

if (codeLines - 6 <= maxLines) { /*根据主题的实际情况将codeLines调整为实际行数 Adjust codeLines to real lines*/
trigger.style.display = 'none';
} else {
trigger.addEventListener("click", function () {
this.classList.toggle("active");
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
}
});

三、一些注意事项

  经过以上修改,文章内插入的代码就可以实现折叠显示的效果了。
  以下是一些注意事项,供大家参考:
(1)直接将JavaScript代码插入html页面时,本地测试正常,但是发布到Github Pages上却不起作用;如果把JavaScript代码存放到js文件中然后再引用,却可以起作用。阿猪一直没搞明白到底是为什么,可能是因为浏览器或者Github Pages的安全机制在搞怪。
(2)CSS代码和JavaScript代码不要重复写入,否则“展开”按钮会失效。
(3)如果你想更改默认的折叠行数,需要注意JavaScript认为的行数与肉眼看到的行数之间的差异,否则可能会出现代码行数很短,但是仍然会出现“展开”按钮的情况。
  JavaScript代码使用textContent.split('\n').length来判断collapsible-content所在标签内的纯文本内容的行数。换行后的空行会占用一行,一些横向显示的嵌套标签也会分别占用一行。例如Chirpy主题使用包含两个columns的<table>显示代码,肉眼看到是一行,但是对JavaScript来说却是两行。
(4)CSS部分添加了美化显示效果的代码。如果你想进一步修改的话,留意与Chirpy主题原有CSS的适配,否则可能会影响代码高亮、复制代码、滚动条等正常功能。