(本文最先发表于Zhu's Blog,未经书面授权许可,任何个人和组织不得以任何形式转载、引用本人的任何文章。本人保留追究侵权者法律责任的权利。)
使用Chirpy主题发表文章时,插入的代码块会全部显示出来。在代码行数比较多的情况下,读者的阅读体验会比较差。阿猪希望能实现CSDN博客那样的折叠展示效果。
经过一番折腾,终于搞定。先上效果图:
一、代码原型
<!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>
之后添加入下代码:
<p class="language-javascript collapsible-trigger collapsible-trigger-css">展开/收起</p>
(6)第26行,插入如下代码:
{% 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
在文件的最下方空白处插入如下代码:
.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;
}
/* Custom scrollbar style for all elements */
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
border-radius: 10px; /* Increase border-radius for a more rounded look */
}
::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.3);
border-radius: 10px; /* Increase border-radius for a more rounded look */
border: 5px solid transparent; /* Reduce border size and use transparent color */
background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.4);
}
/* Edge and other browsers scrollbar style */
html {
scrollbar-width: thin; /* Use 'thin' instead of a fixed width */
scrollbar-color: rgba(0, 0, 0, 0.3) transparent; /* Use 'transparent' color for scrollbar track */
}
3、创建\assets\js\collapsible.js
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代码中对显示效果做了适当的调整,好让代码框看起来更美观。保留了横向滚动条,隐藏了纵向滚动条。使用障眼法让滚动条看起来更细更圆滑。