注意:本站已迁移至 Hugo。请访问本站「历史节点」获取有关 Hexo 的内容。

使用 Hexo 过滤器(Filter)实现 Fluid 主题的代码折叠。

过滤器简介

过滤器(Filter)细节参见「官方文档」。

过滤器(Filter)用于修改特定文件,Hexo 将这些文件依序传给过滤器,而过滤器可以针对文件进行修改。注册过滤器的方式如下:

JavaScript
hexo.extend.filter.register(
  type,
  function () {
    // do something...
  },
  priority
);

priority 是过滤器的优先级,priority 值越小,过滤器会越早执行,默认的 priority 是 10。

思路

我们可以自定义一个过滤器,在文章完成渲染后增加折叠功能的代码。

折叠功能借助 Bootstrap - Collapse 实现。此外,Fluid 主题已引入 Bootstrap,我们无需再次引入。

实现

scripts/ 目录下新建文件 <fileName>.js,文件名自定,内容如下:

JavaScript
"use strict";

// 获取唯一 ID
function getUuid() {
  return Math.random().toString(36).substring(2, 8) + Date.now().toString(36);
}

hexo.extend.filter.register(
  "after_post_render",
  (data) => {
    const { line_number, lib } = hexo.theme.config.code.highlight;

    let reg;
    if (lib === "highlightjs") {
      if (line_number) {
        reg = /(<figure class="highlight.+?>)(.+?hljs (.*?)".+?)(<\/figure>)/gims;
      } else {
        reg = /(<div class="code-wrapper.+?>)(.+?hljs (.*?)".+?)(<\/div>)/gims;
      }
    } else if (lib === "prismjs") {
      reg = /(<div class="code-wrapper.+?>)(.+?data-language="(.*?)".+?)(<\/div>)/gims;
    }

    data.content = data.content.replace(reg, (match, begin, inner, lang, end, offset, string) => {
      const collapseId = `collapse-${getUuid()}`;
      //                             ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 设置折叠按钮图标,此处使用 GitHub 图标
      const collapseBtn = `<i class="iconfont icon-github-fill" type="button" data-toggle="collapse" data-target="#${collapseId}"></i>`;
      const collapseDiv = `<div class="collapse show" id="${collapseId}">${inner}</div>`;
      const langSpan = `<span>${lang}</span>`;
      return begin + collapseBtn + langSpan + collapseDiv + end;
    });
    return data;
  },
  10000 // 应该在完成其他渲染后执行,因此将优先级设大一点
);

此时的效果如图(使用 highlightjs):

demo-1

增加相应的样式,进行美化:

Stylus
.markdown-body .highlight table,
.markdown-body .code-wrapper pre {
  border-radius: 0 0 0.5rem 0.5rem;
}

.markdown-body .highlight,
.markdown-body .code-wrapper {
  background-color: #e6ebf1;
  border-radius: 0.625rem;

  // 折叠图标
  > i {
    color: #777777;
    margin-left: 10px;
    line-height: 2rem;
    transform: none;
    transition: color 0.2s ease-in-out, transform 0.2s ease-in-out;

    &.collapsed {
      transform: rotate(-90deg);
    }
  }

  // 代码语言
  > span {
    color: #777777;
    margin-left: 10px;
    font-weight: bold;
  }
}

[data-user-color-scheme='dark'] {
  .markdown-body .highlight,
  .markdown-body .code-wrapper {
    background-color: #696969;
    transition: background-color 0.2s ease-in-out;

    > i {
      color: #c4c6c9;
    }

    > span {
      color: #c4c6c9;
      transition: color 0.2s ease-in-out;
    }
  }
}

效果如下:

demo-2

参考