Hexo 神复现洛谷 Md 插件!

· · 科技·工程

前言

:::info[Tip:]{open} 可以在我的博客观看以获得更好的阅读体验哦! :::

OIer 都知道,洛谷中有个 Markdown 插件,非常好用,效果如下:

:::info[这是一个提示] 我是提示内容。 :::

:::::warning[我是父容器]

我是一些文字。

::::success[我是子容器 1]{open} 我是内容 1。 ::::

我是一些文字。

::::success[我是子容器 2]{open} :::error[我是子容器 3]{open} 我是内容 2。 ::: ::::

我是一些文字。

:::::

:::epigraph[——otto] 大家好啊,我是说的道理。 :::

:::align{left} 居左内容。 :::

:::align{center} 居中内容。 :::

:::align{right} 居右内容。 :::

源码:

:::info[这是一个提示]
我是提示内容。
:::

:::::warning[我是父容器]

我是一些文字。

::::success[我是子容器 1]{open}
我是内容 1。
::::

我是一些文字。

::::success[我是子容器 2]{open}
:::error[我是子容器 3]{open}
我是内容 2。
:::
::::

我是一些文字。

:::::

:::epigraph[——otto]
大家好啊,我是说的道理。
:::

:::align{left}
居左内容。
:::

:::align{center}
居中内容。
:::

:::align{right}
居右内容。
:::

还有更多……

尽管安知鱼主题自带很多标签外挂,但仍然无法满足复制洛谷文章到博客编写习惯性的需求,于是,我全网首发了在 Hexo 中使用洛谷 Md 插件教程。

:::info[闲话] 由于不良习惯,我的所有 Markdown 文章编写均遵循洛谷的 专栏全站推荐规范、洛谷主题库题解规范和如何用 Markdown 和 LaTeX 写一篇排版整齐的题解?。 :::

方法

:::align{center} 知其然,知其所以然 :::

用 Javasript 自定义 Hexo 的 markdown 解析,用正则匹配把标识等进行匹配,转换为 Html,最后由 Css 完成样式。

实现

:::warning{open} 本教程以 anzhiyu 主题为例,其他主题亦可,视情况更改 Css 文件目录和引用方式,参见你的博客主题的文档以后可能会更新下这篇文章,搞个多主题支持。 :::

首先,在博客中新建 Css (~/themes/···(主题名称)/source/css/custom_marked.css)粘贴以下代码并引入(Anzhiyu 主题可以在 config.yml 中的 Inject.head 配置项中引入)。

:::success[代码]

.align-left {
  text-align: left !important;
}

.align-center {
  text-align: center !important;
}

.align-right {
  text-align: right !important;
}

.epigraph {
  width: 40%;
  margin-left: 60%;
}

.epigraph > :last-child {
  margin-top: 0;
  border-top: 1px solid #888;
  text-align: right;
}

summary {
  list-style: none;
  -webkit-user-select: none;
  user-select: none;
  outline: 0;
  margin: 0;
  position: relative;
  padding-left: 24px;
  font-weight: 700;
  list-style: none;
  display: list-item;
  min-height: 1em;
}

.foldable {
  padding: 0.5em 1em;
  margin: 1em 0 1em 0.2em;
  border-left-width: 5px;
  border-left-style: solid;
  overflow: hidden;
}

.foldable.info {
  border-left-color: rgb(52, 152, 219);
}

.foldable.warning {
  border-left-color: rgb(255, 193, 22);
}

.foldable.success {
  border-left-color: rgb(82, 196, 26);
}

.foldable.error {
  border-left-color: rgb(231, 76, 60);
}

.foldable.bug {
  border-left-color: rgb(231, 76, 60);
}

.foldable.flask {
  border-left-color: rgb(155, 89, 182);
}

details.info > summary {
  color: rgb(52, 152, 219);
}

details.warning > summary {
  color: rgb(255, 193, 22);
}

details.success > summary {
  color: rgb(82, 196, 26);
}

details.error > summary {
  color: rgb(231, 76, 60);
}

details.bug > summary {
  color: rgb(231, 76, 60);
}

details.flask > summary {
  color: rgb(155, 89, 182);
}

details.info > summary::before {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>');
}

details.success > summary::before {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>');
}

details.warning > summary::before {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384c13.3 0 24 10.7 24 24V264c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384c13.3 0 24 10.7 24 24V264c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>');
}

details.error > summary::before {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"%20viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>');
}

details.bug > summary::before {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons:CC BY 4.0,Fonts:SIL OFL 1.1,Code:MIT License) Copyright 2024 Fonticons,Inc. --><path d="M256 0c53 0 96 43 96 96l0 3.6c0 15.7-12.7 28.4-28.4 28.4l-135.1 0c-15.7 0-28.4-12.7-28.4-28.4l0-3.6c0-53 43-96 96-96zM41.4 105.4c12.5-12.5 32.8-12.5 45.3 0l64 64c.7 .7 1.3 1.4 1.9 2.1c14.2-7.3 30.4-11.4 47.5-11.4l112 0c17.1 0 33.2 4.1 47.5 11.4c.6-.7 1.2-1.4 1.9-2.1l64-64c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3l-64 64c-.7 .7-1.4 1.3-2.1 1.9c6.2 12 10.1 25.3 11.1 39.5l64.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c0 24.6-5.5 47.8-15.4 68.6c2.2 1.3 4.2 2.9 6 4.8l64 64c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-63.1-63.1c-24.5 21.8-55.8 36.2-90.3 39.6L272 240c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 239.2c-34.5-3.4-65.8-17.8-90.3-39.6L86.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l64-64c1.9-1.9 3.9-3.4 6-4.8C101.5 367.8 96 344.6 96 320l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64.3 0c1.1-14.1 5-27.5 11.1-39.5c-.7-.6-1.4-1.2-2.1-1.9l-64-64c-12.5-12.5-12.5-32.8 0-45.3z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons:CC BY 4.0,Fonts:SIL OFL 1.1,Code:MIT License) Copyright 2024 Fonticons,Inc. --><path d="M256 0c53 0 96 43 96 96l0 3.6c0 15.7-12.7 28.4-28.4 28.4l-135.1 0c-15.7 0-28.4-12.7-28.4-28.4l0-3.6c0-53 43-96 96-96zM41.4 105.4c12.5-12.5 32.8-12.5 45.3 0l64 64c.7 .7 1.3 1.4 1.9 2.1c14.2-7.3 30.4-11.4 47.5-11.4l112 0c17.1 0 33.2 4.1 47.5 11.4c.6-.7 1.2-1.4 1.9-2.1l64-64c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3l-64 64c-.7 .7-1.4 1.3-2.1 1.9c6.2 12 10.1 25.3 11.1 39.5l64.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c0 24.6-5.5 47.8-15.4 68.6c2.2 1.3 4.2 2.9 6 4.8l64 64c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-63.1-63.1c-24.5 21.8-55.8 36.2-90.3 39.6L272 240c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 239.2c-34.5-3.4-65.8-17.8-90.3-39.6L86.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l64-64c1.9-1.9 3.9-3.4 6-4.8C101.5 367.8 96 344.6 96 320l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64.3 0c1.1-14.1 5-27.5 11.1-39.5c-.7-.6-1.4-1.2-2.1-1.9l-64-64c-12.5-12.5-12.5-32.8 0-45.3z"/></svg>');
}

details.flask > summary::before {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons:CC BY 4.0,Fonts:SIL OFL 1.1,Code:MIT License) Copyright 2024 Fonticons,Inc. --><path d="M288 0L160 0 128 0C110.3 0 96 14.3 96 32s14.3 32 32 32l0 132.8c0 11.8-3.3 23.5-9.5 33.5L10.3 406.2C3.6 417.2 0 429.7 0 442.6C0 480.9 31.1 512 69.4 512l309.2 0c38.3 0 69.4-31.1 69.4-69.4c0-12.8-3.6-25.4-10.3-36.4L329.5 230.4c-6.2-10.1-9.5-21.7-9.5-33.5L320 64c17.7 0 32-14.3 32-32s-14.3-32-32-32L288 0zM192 196.8L192 64l64 0 0 132.8c0 23.7 6.6 46.9 19 67.1L309.5 320l-171 0L173 263.9c12.4-20.2 19-43.4 19-67.1z"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons:CC BY 4.0,Fonts:SIL OFL 1.1,Code:MIT License) Copyright 2024 Fonticons,Inc. --><path d="M288 0L160 0 128 0C110.3 0 96 14.3 96 32s14.3 32 32 32l0 132.8c0 11.8-3.3 23.5-9.5 33.5L10.3 406.2C3.6 417.2 0 429.7 0 442.6C0 480.9 31.1 512 69.4 512l309.2 0c38.3 0 69.4-31.1 69.4-69.4c0-12.8-3.6-25.4-10.3-36.4L329.5 230.4c-6.2-10.1-9.5-21.7-9.5-33.5L320 64c17.7 0 32-14.3 32-32s-14.3-32-32-32L288 0zM192 196.8L192 64l64 0 0 132.8c0 23.7 6.6 46.9 19 67.1L309.5 320l-171 0L173 263.9c12.4-20.2 19-43.4 19-67.1z"/></svg>');
}

summary::before {
  content: "";
  background-color: currentcolor;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  margin-right: 8px;
}

summary:after {
  content: "";
  background-color: currentcolor;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20256%20512%22%3E%3Cpath%20d%3D%22M246.6%20278.6c12.5-12.5%2012.5-32.8%200-45.3l-128-128c-9.2-9.2-22.9-11.9-34.9-6.9s-19.8%2016.6-19.8%2029.6l0%20256c0%2012.9%207.8%2024.6%2019.8%2029.6s25.7%202.2%2034.9-6.9l128-128z%22%2F%3E%3C%2Fsvg%3E");;
  mask-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20256%20512%22%3E%3Cpath%20d%3D%22M246.6%20278.6c12.5-12.5%2012.5-32.8%200-45.3l-128-128c-9.2-9.2-22.9-11.9-34.9-6.9s-19.8%2016.6-19.8%2029.6l0%20256c0%2012.9%207.8%2024.6%2019.8%2029.6s25.7%202.2%2034.9-6.9l128-128z%22%2F%3E%3C%2Fsvg%3E");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  transition: transform 0.2s ease;
}

details[open] > summary::after {
  transform: translateY(-50%) rotate(90deg);
}

:::

然后直接在 ~/themes/···(主题名称)/scripts 中新建 custom_marked.js(也可以是别的名字),粘贴以下代码即可,不用引入

:::success[代码]

// 允许使用的折叠容器类型集合
const allowedFoldableTypes = new Set(['info', 'warning', 'success', 'error', 'bug', 'flask']);

/**
 * 使用 Hexo 同步渲染接口将文本渲染为 Markdown 格式
 * @param {string} content 待渲染的文本内容
 * @returns {string} 渲染后的 HTML 内容
 */
function renderMarkdown(content) {
  return hexo.render.renderSync({ text: content.trim(), engine: 'markdown' });
}

/**
 * 根据块类型生成对应的自定义 HTML 结构
 * @param {string} blockType 块类型
 * @param {string} title 块标题
 * @param {string} opt 块配置选项
 * @param {string} body 块内部内容
 * @returns {string|null} 生成的 HTML 字符串,未知类型返回 null
 */
function renderCustomBlock(blockType, title, opt, body) {
  const type = blockType.toLowerCase(); // 统一转换为小写,兼容大小写写法
  const content = renderMarkdown(body.trim()); // 渲染块内的 Markdown 内容

  // 文本对齐块:生成带对齐类名的 div 容器
  if (type === 'align') {
    const dir = title ? title.trim() : 'left'; // 未指定方向时默认左对齐
    return `\n<div class="align-${dir}">\n${content}\n</div>\n`;
  }

  // 题记/引语块:生成带作者信息的引语容器
  if (type === 'epigraph') {
    const author = title ? `<p class="epigraph-author">${title}</p>` : ''; // 标题作为作者信息
    return `\n<div class="epigraph">\n${content}${author}\n</div>\n`;
  }

  // 可折叠容器:生成 details/summary 结构
  if (allowedFoldableTypes.has(type)) {
    const openAttr = opt && opt.includes('open') ? ' open' : ''; // 包含 open 选项则默认展开
    const summary = title ? title.trim() : '详情'; // 未指定标题时默认显示"详情"
    return `\n<details class="foldable ${type}"${openAttr}>\n  <summary>${summary}</summary>\n  <div>\n${content}\n  </div>\n</details>\n`;
  }

  return null; // 未知类型返回 null,保留原始标记
}

/**
 * 解析 Markdown 内容中的自定义块语法,构建 AST 并渲染为最终 HTML
 * @param {string} content 原始 Markdown 内容
 * @returns {string} 处理后的 HTML 内容
 */
function parseCustomBlocks(content) {
  const lines = content.split(/\r?\n/); // 按行分割内容,兼容 Windows/Unix 换行符
  const root = { type: 'root', children: [] }; // 抽象语法树根节点
  const stack = [root]; // 栈结构,用于处理嵌套的块层级
  let codeFence = null; // 代码块标记,记录当前是否处于代码块内及围栏字符

  // 自定义块开始标记正则:匹配 :::type[title]{opt} 格式
  const openRule = /^\s*(:{3,})([a-zA-Z]\w*)(?:\s*\[([^\]]*)\])?(?:\s*\{([^}]*)\})?\s*$/;
  // 自定义块结束标记正则:匹配 ::: 格式
  const closeRule = /^\s*(:{3,})\s*$/;

  for (const line of lines) {
    // ---------- 代码块处理逻辑 ----------
    const fenceMatch = line.match(/^\s*(`{3,}|~{3,})/);
    if (fenceMatch) {
      const fence = fenceMatch[1];
      if (!codeFence) {
        codeFence = fence; // 进入代码块,记录围栏字符
      } else if (codeFence === fence) {
        codeFence = null; // 退出代码块,清空标记
      }
      // 代码块标记行直接作为文本保留
      stack[stack.length - 1].children.push({ type: 'text', value: line });
      continue;
    }

    // 当前处于代码块内时,所有行均作为纯文本处理,不解析自定义块
    if (codeFence) {
      stack[stack.length - 1].children.push({ type: 'text', value: line });
      continue;
    }

    // ---------- 自定义块开始标记处理 ----------
    const openMatch = line.match(openRule);
    if (openMatch) {
      const level = openMatch[1].length; // 冒号数量代表块的嵌套层级
      const blockType = openMatch[2].toLowerCase(); // 块类型
      const title = openMatch[3] || ''; // 块标题(方括号内内容)
      const opt = openMatch[4] || ''; // 块配置选项(大括号内内容)
      // 创建块节点并加入语法树
      const node = { type: 'block', level, blockType, title, opt, children: [] };
      stack[stack.length - 1].children.push(node);
      stack.push(node); // 压入栈顶,成为当前作用域
      continue;
    }

    // ---------- 自定义块结束标记处理 ----------
    const closeMatch = line.match(closeRule);
    if (closeMatch) {
      const level = closeMatch[1].length;
      // 结束标记层级与栈顶块层级一致时,弹出栈顶,闭合当前块
      if (stack.length > 1 && stack[stack.length - 1].level === level) {
        stack.pop();
        continue;
      }
    }

    // ---------- 普通文本行处理 ----------
    stack[stack.length - 1].children.push({ type: 'text', value: line });
  }

  return renderNode(root); // 递归渲染语法树,生成最终 HTML
}

/**
 * 递归渲染语法树节点,生成最终 HTML 字符串
 * @param {object} node 语法树节点
 * @returns {string} 渲染后的文本内容
 */
function renderNode(node) {
  // 根节点:遍历渲染所有子节点并拼接
  if (node.type === 'root') {
    return node.children.map(renderNode).join('\n');
  }
  // 文本节点:直接返回原始文本
  if (node.type === 'text') {
    return node.value;
  }
  // 块节点:先递归渲染内部内容,再包裹对应 HTML 结构
  if (node.type === 'block') {
    const inner = node.children.map(renderNode).join('\n');
    const customHtml = renderCustomBlock(node.blockType, node.title, node.opt, inner);
    // 已知类型返回自定义 HTML,未知类型保留原始标记
    if (customHtml !== null) {
      return customHtml;
    }
    // 未知块类型:还原原始的自定义标记语法
    const start = `${':'.repeat(node.level)}${node.blockType}${node.title ? `[${node.title}]` : ''}${node.opt ? `{${node.opt}}` : ''}`;
    const end = ':'.repeat(node.level);
    return `${start}\n${inner}\n${end}`;
  }
  return '';
}

// 注册 Hexo 前置渲染过滤器,在 Markdown 渲染前处理自定义块
hexo.extend.filter.register('before_post_render', data => {
  if (typeof data.content !== 'string') return data; // 非字符串内容跳过处理
  // 输出调试日志,标记当前处理的文章
  hexo.log.debug('custom_marked before_post_render', data.source || data.path || data.title || 'unknown');
  data.content = parseCustomBlocks(data.content); // 执行自定义块解析与渲染
  return data;
});

:::

AI 声明:代码注释使用智谱清言 GLM-5.2 大模型进行修改和润色。

:::info[为什么不用引入?]{open} 与前面引入的 Css 不同的是,任意主题的目录 ~/themes/···(主题名称)/scripts 功能都一样,Hexo 解析时都会运行此目录下的所有 Javascript 文件。 :::

:::error[可能的错误] 一不小心放到了 ~/themes/anzhiyu/source/js/custom_marked.js 里。 :::

完结

hexo new "plugin-test"
hexo cl&&hexo g&&hexo s

赶紧在新文章里尝试并体验一下吧!是不是很好用?如果有什么建议,可以在评论区告诉我。