Files
blog/posts/a6ab0925/index.html
T
2026-06-19 13:28:19 +08:00

974 lines
74 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="这篇文章介绍了如何使用插件来自定义Hexo博客的页脚菜单。首先,通过npm安装了hexo-butterfly-footer-marcus插件,并根据需要安装了yamljs插件。接着,在博客的配置文件中添加了相关配置信息,包括页脚美化、图标链接、作者信息等。文章还提供了具体的参数释义和使用方法,指导读者如何填写配置项和修改源码来调整页脚样式和布局。最后,文章还提到了如何解决在黑暗模式下修改按钮层级的问题,并提供了相关的代码修改示例。"><link rel="icon" href="/images/Bi.ico"><script defer src="https://umami.biss.click/script.js" data-website-id="3d97b310-b241-4fc6-bc9c-68e317fc7d42"></script><script>window.SITE_CONFIG = {"site":{"url":"https://blog.biss.click","name":"Bi's Blog","description":"Personal blog by biss.","language":"zh-CN","domain":"blog.biss.click","slogan":"好奇心转化为代码的空间。","startTime":"2025-01-01T00:00:00+08:00","copyrightStartYear":2025,"license":"内容采用 CC BY-NC-SA 4.0 协议"},"author":{"name":"biss","email":"bishsh2006@gmail.com","github":"https://github.com/bishshi","avatar":"https://free.picui.cn/free/2025/08/10/689845496a283.png"},"comments":{"envId":"https://comment.biss.click","region":"","script":"https://cdn.jsdelivr.net/npm/twikoo@1.7.7/dist/twikoo.min.js"},"analytics":{"umami":{"script":"https://umami.biss.click/script.js","websiteId":"3d97b310-b241-4fc6-bc9c-68e317fc7d42","statsEndpoint":"https://blogumami.biss.click"}},"talks":{"apiUrl":"https://mm.biss.click/api/echo/page","pageSize":30,"homeLimit":6,"cacheKey":"talksCache","cacheTimeKey":"talksCacheTime","cacheDurationMs":1800000,"fallbackAvatar":"https://free.picui.cn/free/2025/08/10/689845496a283.png"},"search":{"apiKey":"2uxQzk7eD2GBCljdSmIiuU3ause7UK9n","server":{"host":"typesense.biss.click","port":"443","protocol":"https"},"indexName":"blogs","searchParams":{"query_by":"title,content","highlight_full_fields":"title,content","per_page":8,"num_typos":1,"typo_tokens_threshold":1,"prefix":true},"ui":{"maxRetries":10,"retryDelay":100,"animationDuration":300,"maxInitRetries":30,"placeholder":"输入关键词寻找故事..."}},"externalLinks":{"waitSeconds":10,"whitelist":["blog.biss.click","biss.click","github.com","localhost","127.0.0.1"]}};</script><script>
(() => {
const storageKey = 'site-theme';
const savedTheme = localStorage.getItem(storageKey);
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
document.documentElement.dataset.theme = savedTheme || systemTheme;
})();
</script><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/instantsearch.css/themes/reset-min.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/@fortawesome/fontawesome-free@6.7.2/css/all.min.css"><title>利用插件自定义页脚菜单 | Bi&#39;s Blog</title><link rel="stylesheet" href="/_astro/BaseLayout.D7kFxpxP.css"></head> <body> <header class="site-header"> <nav class="nav"> <a class="brand" href="/">Bi&#39;s Blog</a> <button class="nav-menu-toggle" type="button" aria-label="打开菜单" aria-expanded="false" data-nav-toggle> <i class="fa-solid fa-bars nav-menu-open" aria-hidden="true"></i> <i class="fa-solid fa-xmark nav-menu-close" aria-hidden="true"></i> </button> <div class="nav-menu" data-nav-menu> <div class="nav-links nav-center"> <a href="/archives/"><i class="fa-solid fa-box-archive nav-icon" aria-hidden="true"></i><span>归档</span></a><a href="/categories/"><i class="fa-solid fa-folder-open nav-icon" aria-hidden="true"></i><span>分类</span></a><a href="/tags/"><i class="fa-solid fa-tags nav-icon" aria-hidden="true"></i><span>标签</span></a><a href="/shuoshuo/"><i class="fa-regular fa-comments nav-icon" aria-hidden="true"></i><span>说说</span></a><a href="/about/"><i class="fa-solid fa-heart nav-icon" aria-hidden="true"></i><span>关于</span></a><a href="/link/"><i class="fa-solid fa-link nav-icon" aria-hidden="true"></i><span>友链</span></a> </div> <div class="nav-links nav-actions"> <button class="nav-random" type="button" onclick="randomPost()" aria-label="前往随机文章" title="前往随机文章"> <i class="fa-solid fa-shuffle nav-icon" aria-hidden="true"></i> <span>随机文章</span> </button> <button class="nav-search search-typesense-trigger" type="button" aria-label="搜索" title="搜索"> <i class="fa-solid fa-magnifying-glass nav-icon" aria-hidden="true"></i> <span>搜索</span> </button> <button class="theme-toggle" type="button" aria-label="切换夜间模式" title="切换夜间模式" data-theme-toggle> <i class="fa-solid fa-sun theme-toggle-sun nav-icon" aria-hidden="true"></i> <i class="fa-solid fa-moon theme-toggle-moon nav-icon" aria-hidden="true"></i> </button> </div> </div> </nav> </header> <main> <section class="post-layout"> <article class="article post-article"> <header class="article-header article-header-cover"> <img class="article-header-cover-img" src="https://pic.biss.click/image/a49d986a-7430-4fa5-89dd-13dee416632f.webp" alt="" loading="eager" decoding="async"> <div class="article-header-content"> <time datetime="2025-08-12T09:19:16.000Z">2025/08/12</time> <h1>利用插件自定义页脚菜单</h1> <div class="article-hero-meta" aria-label="文章信息"> <span>发布于 2025/08/12</span> <a href="/categories/site-notes/">建站手札</a> <span>总字数:1.6k</span> <span>阅读时长:5 分钟</span> </div> </div> </header> <section class="article-summary-card" aria-label="AI 文章摘要"> <div class="article-summary-dots" aria-hidden="true"> <span></span> <span></span> <span></span> </div> <p class="article-summary-content"> <span class="article-summary-text" data-summary-text="这篇文章介绍了如何使用插件来自定义Hexo博客的页脚菜单。首先,通过npm安装了hexo-butterfly-footer-marcus插件,并根据需要安装了yamljs插件。接着,在博客的配置文件中添加了相关配置信息,包括页脚美化、图标链接、作者信息等。文章还提供了具体的参数释义和使用方法,指导读者如何填写配置项和修改源码来调整页脚样式和布局。最后,文章还提到了如何解决在黑暗模式下修改按钮层级的问题,并提供了相关的代码修改示例。">这篇文章介绍了如何使用插件来自定义Hexo博客的页脚菜单。首先,通过npm安装了hexo-butterfly-footer-marcus插件,并根据需要安装了yamljs插件。接着,在博客的配置文件中添加了相关配置信息,包括页脚美化、图标链接、作者信息等。文章还提供了具体的参数释义和使用方法,指导读者如何填写配置项和修改源码来调整页脚样式和布局。最后,文章还提到了如何解决在黑暗模式下修改按钮层级的问题,并提供了相关的代码修改示例。</span> <span class="article-summary-caret" aria-hidden="true"></span> </p> <div class="article-summary-footer"> <span class="article-summary-brand"> <span aria-hidden="true"></span>
AI摘要
</span> <span class="article-summary-model">QWEN</span> </div> </section> <div class="prose" data-toc="[{&quot;depth&quot;:1,&quot;text&quot;:&quot;安装&quot;,&quot;id&quot;:&quot;安装&quot;},{&quot;depth&quot;:1,&quot;text&quot;:&quot;添加配置信息&quot;,&quot;id&quot;:&quot;添加配置信息&quot;},{&quot;depth&quot;:1,&quot;text&quot;:&quot;参数释义&quot;,&quot;id&quot;:&quot;参数释义&quot;},{&quot;depth&quot;:1,&quot;text&quot;:&quot;参考&quot;,&quot;id&quot;:&quot;参考&quot;}]"> <h1 id="安装">安装</h1>
<p>安装插件,在博客根目录[Blogroot]下打开终端,运行以下指令:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">npm</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> hexo-butterfly-footer-marcus</span><span style="color:#79B8FF"> --save</span></span></code></pre>
<p>如果需要随机友链接的话,再运行以下指令:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">npm</span><span style="color:#9ECBFF"> i</span><span style="color:#9ECBFF"> yamljs</span><span style="color:#79B8FF"> --save</span></span></code></pre>
<h1 id="添加配置信息">添加配置信息</h1>
<p>以下为写法示例 在站点配置文件_config.yml或者主题配置文件_config.butterfly.yml中添加</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="yml"><code><span class="line"><span style="color:#6A737D">#hexo-butterfly-footer-marcus</span></span>
<span class="line"><span style="color:#6A737D">#see https://blog.marcus233.top/p/footer.html</span></span>
<span class="line"><span style="color:#85E89D">footer_beautify</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> priority</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">5</span><span style="color:#6A737D"> #过滤器优先权</span></span>
<span class="line"><span style="color:#85E89D"> enable_page</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">all</span><span style="color:#6A737D"> # 应用页面</span></span>
<span class="line"><span style="color:#85E89D"> layout</span><span style="color:#E1E4E8">: </span><span style="color:#6A737D"># 挂载容器类型</span></span>
<span class="line"><span style="color:#85E89D"> type</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">id</span></span>
<span class="line"><span style="color:#85E89D"> name</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">footer</span></span>
<span class="line"><span style="color:#85E89D"> index</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">1</span></span>
<span class="line"><span style="color:#85E89D"> footer_icons</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> left</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-solid fa-compass</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://www.marcus233.top/</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">个人主页</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">out</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-brands fa-qq</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://res.abeim.cn/api/qq/?qq=3105950984</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">联系QQ</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">out</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-brands fa-weixin</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/wechat/</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">联系微信</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-solid fa-envelope</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">mailto:marcus@marcus233.top</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">发送邮件</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">out</span></span>
<span class="line"><span style="color:#85E89D"> right</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-brands fa-github</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://github.com/Marcusyyds</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Github主页</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">out</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-brands fa-bilibili</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://space.bilibili.com/1024450661</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">哔哩哔哩主页</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">out</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-solid fa-star</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/stars/</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">藏宝阁</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">icon</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">fa-solid fa-comment</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/message/</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">留言</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#85E89D"> footer_logo</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> url</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://img01.anheyu.com/useruploads/8/2022/12/15/639adf5b8806a.png</span></span>
<span class="line"><span style="color:#85E89D"> footer_group</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> footer_group_link</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">group_title</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">直达</span></span>
<span class="line"><span style="color:#85E89D"> footer_links</span><span style="color:#E1E4E8">: </span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">藏宝阁</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/stars/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">优秀句子</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/sentence/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">空间说说</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/zone/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">友链订阅</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/fcircle/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">切换背景</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/bg/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">group_title</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">关于</span></span>
<span class="line"><span style="color:#85E89D"> footer_links</span><span style="color:#E1E4E8">: </span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">关于我</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/about/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">RSS订阅</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/atom.xml</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">站点监控</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://uptime.marcus233.top/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">out</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">更新记录</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/timeline/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">我的相册</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/picture/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">group_title</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">分类</span></span>
<span class="line"><span style="color:#85E89D"> footer_links</span><span style="color:#E1E4E8">: </span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">博客相关</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/categories/博客相关</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">生活点滴</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/categories/生活点滴</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span><span style="color:#E1E4E8"> </span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">资源分享</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/categories/资源分享</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">学习笔记</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/categories/学习笔记</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span><span style="color:#E1E4E8"> </span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">实用教程</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/categories/实用教程</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span><span style="color:#E1E4E8"> </span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">查看全部</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">/categories/</span></span>
<span class="line"><span style="color:#85E89D"> class</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">in</span><span style="color:#E1E4E8"> </span></span>
<span class="line"><span style="color:#85E89D"> footer_friend_links</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> number</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">5</span></span>
<span class="line"><span style="color:#85E89D"> footer_bottom</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> copyright</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> author</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Marcus</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://marcus233.top/</span></span>
<span class="line"><span style="color:#85E89D"> time</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">2022</span></span>
<span class="line"><span style="color:#85E89D"> left</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">雨云</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">本站CDN支持</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://rainyun.com/</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">网盾星球</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">本站CDN防护主要提供商:网盾星球</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://www.netdun.net/</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">萌ICP备20230221</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">萌ICP备20230221</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://icp.gov.moe/?keyword=20230221</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">萌ICP备20236688</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">萌ICP备20236688</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://icp.gov.moe/?keyword=20236688</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">萌ICP备20230002</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">萌ICP备20230002</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://icp.gov.moe/?keyword=20230002</span></span>
<span class="line"><span style="color:#85E89D"> right</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Hexo</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">框架</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://hexo.io/zh-cn/</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#85E89D">text</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">Butterfly</span></span>
<span class="line"><span style="color:#85E89D"> desrc</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">主题</span></span>
<span class="line"><span style="color:#85E89D"> link</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://butterfly.js.org/</span></span>
<span class="line"><span style="color:#85E89D"> runtime</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D"> enable</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">true</span></span>
<span class="line"><span style="color:#85E89D"> time</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">2022/08/09 00:00:00</span></span>
<span class="line"><span style="color:#85E89D"> footer_css</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://cdn1.tianli0.top/npm/hexo-butterfly-footer-marcus/lib/footer.min.css</span></span>
<span class="line"><span style="color:#85E89D"> footer_js</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">https://cdn1.tianli0.top/npm/hexo-butterfly-footer-marcus/lib/footer.min.js</span></span></code></pre>
<p>请自行下载footer_js修改建站日期
如果开启了随机友联,根目录下却没有link.json,请参考(页脚的随机友链)[<a href="https://blog.shineyu.cn/footer-random-flink.html">https://blog.shineyu.cn/footer-random-flink.html</a>]</p>
<h1 id="参数释义">参数释义</h1>
<table><thead><tr><th>参数</th><th>备选值/类型</th><th>释义</th></tr></thead><tbody><tr><td>enable</td><td>true/false</td><td>【必选】控制开关</td></tr><tr><td>priority</td><td>number</td><td>【可选】过滤器优先级,数值越小,执行越早,默认为10,选填</td></tr><tr><td>enable_page</td><td>path/all</td><td>【可选】填写想要应用的页面的相对路径(即路由地址),如根目录就填’/‘,分类页面就填’/categories/‘。若要应用于所有页面,就填’all’,默认为all</td></tr><tr><td>exclude</td><td>path</td><td>【可选】填写想要屏蔽的页面,可以多个。仅当enable_page为’all’时生效。写法见示例。原理是将屏蔽项的内容逐个放到当前路径去匹配,若当前路径包含任一屏蔽项,则不会挂载。</td></tr><tr><td>layout.type</td><td>id/class</td><td>【可选】挂载容器类型,填写id或class,不填则默认为id</td></tr><tr><td>layout.name</td><td>text</td><td>【必选】挂载容器名称</td></tr><tr><td>layout.index</td><td>0和正整数</td><td>【可选】前提是layout.type为class,因为同一页面可能有多个class,此项用来确认究竟排在第几个顺位</td></tr><tr><td>insertposition</td><td>text</td><td>beforebegin’:元素自身的前面。’afterbegin’:插入元素内部的第一个子节点之前。’beforeend’:插入元素内部的最后一个子节点之后。’afterend’:插入元素自身的后面。</td></tr><tr><td>footer_icons.enable</td><td>true/false</td><td>【必选】icon控制开关</td></tr><tr><td>*.text</td><td>text</td><td>【必选】显示文字</td></tr><tr><td>*.icon</td><td>class</td><td>【必选】icon(例:fa-solid fa-commet)</td></tr><tr><td>*.desrc</td><td>text</td><td>【必选】a标签内的title选项</td></tr><tr><td>*.class</td><td>in/out</td><td>【必选】站内/外链接(站内:in,站外:out)</td></tr><tr><td>*.link</td><td>url</td><td>【必选】链接</td></tr><tr><td>footer_logo.enable</td><td>true/false</td><td>【必选】icon内logo控制开关</td></tr><tr><td>footer_group.enable</td><td>true/false</td><td>【必选】group控制开关</td></tr><tr><td>footer_friend_links.enable</td><td>true/false</td><td>【必选】随机友联开关</td></tr><tr><td>footer_friend_link.number</td><td>正整数</td><td>【可选】随机友联数量</td></tr><tr><td>footer_bottom.copyright.enable</td><td>true/false</td><td>【必选】copyright开关</td></tr><tr><td>footer_bottom.runtime.enable</td><td>true/false</td><td>【必选】网站运行时间开关</td></tr><tr><td>footer_css</td><td>url</td><td>【必选】css链接</td></tr><tr><td>footer_js</td><td>url</td><td>【必选】js链接</td></tr></tbody></table>
<p>使用方法
填写配置项
需改动源码的地方</p>
<p><code>themes\butterfly\layout\includes\layout.pug</code>43行(修改页脚背景色的bug)</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="pug"><code><span class="line"><span style="color:#F97583"> else</span></span>
<span class="line"><span style="color:#E1E4E8"> - </span><span style="color:#F97583">var</span><span style="color:#E1E4E8"> footer_bg </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> ''</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">- footer#</span><span style="color:#B392F0">footer</span><span style="color:#E1E4E8">(style</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">footer_bg)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">+ footer#footer(style='background: transparent')</span></span>
<span class="line"><span style="color:#79B8FF"> !=</span><span style="color:#B392F0">partial</span><span style="color:#E1E4E8">(</span><span style="color:#9ECBFF">'includes/footer'</span><span style="color:#E1E4E8">, {}, {cache: </span><span style="color:#79B8FF">true</span><span style="color:#E1E4E8">})</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583"> else</span></span>
<span class="line"><span style="color:#F97583"> include</span><span style="color:#FFAB70"> ./404.pug</span></span></code></pre>
<p>去掉+号
<code>themes\butterfly\source\css\_mode\darkmode.styl</code>43行(修改黑暗模式按钮层级的bug)</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span> #web_bg:before,</span></span>
<span class="line"><span></span></span>
<span class="line"><span>- #footer:before,</span></span>
<span class="line"><span> #page-header:before</span></span>
<span class="line"><span> position: absolute</span></span>
<span class="line"><span> width: 100%</span></span>
<span class="line"><span> height: 100%</span></span>
<span class="line"><span> background-color: alpha($dark-black, .7)</span></span>
<span class="line"><span> content: ''</span></span></code></pre>
<h1 id="参考">参考</h1>
<a class="hexo-link-card" href="[https://blog.marcus233.top/p/footer.html" target="_blank" rel="external nofollow noopener noreferrer">
<span class="hexo-link-card__icon" aria-hidden="true">M</span>
<span class="hexo-link-card__body">
<strong>Marcus的博客</strong>
<span>Marcus</span>
</span>
</a>](https://blog.marcus233.top/p/footer.html%})
<a class="hexo-link-card" href="[https://github.com/sysiocn/hexo-butterfly-footer-marcus" target="_blank" rel="external nofollow noopener noreferrer">
<span class="hexo-link-card__icon" aria-hidden="true">G</span>
<span class="hexo-link-card__body">
<strong>GitHub开源</strong>
<span>github</span>
</span>
</a>](https://github.com/sysiocn/hexo-butterfly-footer-marcus%}) </div> <section class="post-copyright-card" aria-label="文章版权信息"> <div class="post-copyright-mark" aria-hidden="true"> <span>CC</span> </div> <div class="post-copyright-main"> <h2>利用插件自定义页脚菜单</h2> <a class="post-copyright-link" href="/posts/a6ab0925/">/posts/a6ab0925/</a> <dl class="post-copyright-meta"> <div> <dt>作者</dt> <dd>biss</dd> </div> <div> <dt>发布于</dt> <dd><time datetime="2025-08-12T09:19:16.000Z">2025/08/12</time></dd> </div> <div> <dt>许可协议</dt> <dd><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noreferrer">CC BY-NC-SA 4.0</a></dd> </div> </dl> </div> <div class="post-copyright-footer"> <div class="post-copyright-tags" aria-label="文章标签"> <a href="/tags/%E7%BD%91%E7%AB%99/">网站</a> </div> <div class="post-copyright-actions" aria-label="文章操作"> <button class="post-copyright-action is-primary post-share-button" type="button" data-share-title="利用插件自定义页脚菜单" data-share-url="https://blog.biss.click/posts/a6ab0925/" title="分享文章"> <svg aria-hidden="true" viewBox="0 0 24 24"> <path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"></path> <path d="M12 16V4"></path> <path d="m7 9 5-5 5 5"></path> </svg> <span>分享</span> </button> <a class="post-copyright-action" href="/rss.xml" title="订阅 RSS"> <svg aria-hidden="true" viewBox="0 0 24 24"> <path d="M5 5a14 14 0 0 1 14 14"></path> <path d="M5 11a8 8 0 0 1 8 8"></path> <path d="M6 18h.01"></path> </svg> <span>订阅</span> </a> <a class="post-copyright-action" href="/about/" title="打赏作者"> <svg aria-hidden="true" viewBox="0 0 24 24"> <path d="M7 8h10"></path> <path d="M8 8V5h8v3"></path> <path d="M6 8h12l-1.5 11h-9L6 8Z"></path> <path d="M10 12h4"></path> </svg> <span>打赏</span> </a> <a class="post-copyright-icon" href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fblog.biss.click%2Fposts%2Fa6ab0925%2F&amp;text=%E5%88%A9%E7%94%A8%E6%8F%92%E4%BB%B6%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A1%B5%E8%84%9A%E8%8F%9C%E5%8D%95" target="_blank" rel="noreferrer" title="分享到 X"> <span aria-hidden="true">x</span> </a> <a class="post-copyright-icon" href="https://service.weibo.com/share/share.php?url=https%3A%2F%2Fblog.biss.click%2Fposts%2Fa6ab0925%2F&amp;title=%E5%88%A9%E7%94%A8%E6%8F%92%E4%BB%B6%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A1%B5%E8%84%9A%E8%8F%9C%E5%8D%95" target="_blank" rel="noreferrer" title="分享到微博"> <span aria-hidden="true"></span> </a> </div> </div> </section> <script>
(() => {
document.querySelectorAll('.post-share-button').forEach((button) => {
button.addEventListener('click', async () => {
const title = button.dataset.shareTitle || document.title;
const url = button.dataset.shareUrl || window.location.href;
const label = button.querySelector('span');
const originalText = label?.textContent || '分享';
try {
if (navigator.share) {
await navigator.share({ title, url });
return;
}
await navigator.clipboard.writeText(url);
if (label) label.textContent = '已复制';
} catch {
if (label) label.textContent = '复制失败';
} finally {
window.setTimeout(() => {
if (label) label.textContent = originalText;
}, 1800);
}
});
});
})();
</script> <section id="post-comment" class="twikoo-comments" aria-label="Comments" data-env-id="https://comment.biss.click" data-region data-path="/posts/a6ab0925/" data-script="https://cdn.jsdelivr.net/npm/twikoo@1.7.7/dist/twikoo.min.js"> <div class="twikoo-comments-head"> <span class="twikoo-comments-icon" aria-hidden="true"> <svg viewBox="0 0 24 24"> <path d="M21 12a8 8 0 0 1-8 8H7l-4 3v-5a8 8 0 1 1 18-6Z"></path> </svg> </span> <div> <h2>Comments</h2> <p>利用插件自定义页脚菜单</p> </div> </div> <div id="twikoo-wrap" class="twikoo-wrap"></div> </section> <script>
(() => {
const root = document.getElementById('post-comment');
const wrap = document.getElementById('twikoo-wrap');
if (!root || !wrap || root.dataset.twikooLoaded === 'true') return;
const envId = root.dataset.envId;
const path = root.dataset.path || window.location.pathname;
const region = root.dataset.region || undefined;
if (!envId) return;
root.dataset.twikooLoaded = 'true';
const initTwikoo = () => {
if (!window.twikoo || typeof window.twikoo.init !== 'function') return;
window.twikoo.init({
el: wrap,
envId,
region,
path,
});
};
if (window.twikoo) {
initTwikoo();
return;
}
const script = document.createElement('script');
script.src = root.dataset.script;
script.defer = true;
script.onload = initTwikoo;
script.onerror = () => {
root.dataset.twikooLoaded = 'false';
};
document.head.appendChild(script);
})();
</script> </article> <aside class="article-sidebar" aria-label="文章侧边栏"> <section class="sidebar-card article-author-card"> <img class="profile-avatar" src="https://free.picui.cn/free/2025/08/10/689845496a283.png" alt="biss" loading="lazy"> <div class="profile-name">biss</div> <div class="article-author-meta"> <span>2025/08/12</span> <a href="/categories/site-notes/">建站手札</a> </div> </section> <section class="sidebar-card article-tags-card"> <h2> <span aria-hidden="true">#</span>
文章标签
<em>1</em> </h2> <div class="article-tag-list" aria-label="文章标签"> <a href="/tags/%E7%BD%91%E7%AB%99/">#网站</a> </div> </section> <div class="article-sticky-sidebar"> <section class="sidebar-card toc-card"> <h2> <span aria-hidden="true"></span>
文章目录
<em>4</em> </h2> <nav class="toc-list toc-tree" aria-label="文章目录" data-toc-tree> <div class="toc-group is-open" data-toc-group data-heading-id="安装"> <a class="toc-link toc-link-main" href="#安装" data-toc-link data-toc-top> <span class="toc-marker" aria-hidden="true"></span> <span>安装</span> </a> </div><div class="toc-group" data-toc-group data-heading-id="添加配置信息"> <a class="toc-link toc-link-main" href="#添加配置信息" data-toc-link data-toc-top> <span class="toc-marker" aria-hidden="true"></span> <span>添加配置信息</span> </a> </div><div class="toc-group" data-toc-group data-heading-id="参数释义"> <a class="toc-link toc-link-main" href="#参数释义" data-toc-link data-toc-top> <span class="toc-marker" aria-hidden="true"></span> <span>参数释义</span> </a> </div><div class="toc-group" data-toc-group data-heading-id="参考"> <a class="toc-link toc-link-main" href="#参考" data-toc-link data-toc-top> <span class="toc-marker" aria-hidden="true"></span> <span>参考</span> </a> </div> </nav> </section> <section class="sidebar-card same-category-card"> <h2> <span aria-hidden="true"></span>
同类文章
<em>8</em> </h2> <div class="same-category-list"> <a href="/posts/4c91a8f2/"> <strong>用 Umami 分享链接给网站信息卡提供统计数据</strong> <time datetime="2026-06-19T08:58:00.000Z">2026/06/19</time> </a><a href="/posts/7e921903/"> <strong>添加网站左上角菜单</strong> <time datetime="2026-02-10T07:11:14.000Z">2026/02/10</time> </a><a href="/posts/f287c563/"> <strong>添加typesense搜索</strong> <time datetime="2026-02-05T13:14:16.000Z">2026/02/05</time> </a><a href="/posts/b5601a7e/"> <strong>自定义字体</strong> <time datetime="2026-01-16T07:47:15.000Z">2026/01/16</time> </a><a href="/posts/5ed2f1e6/"> <strong>在侧边栏添加日历和倒计时</strong> <time datetime="2026-01-16T07:47:07.000Z">2026/01/16</time> </a><a href="/posts/3a26a97a/"> <strong>为博客添加CMS系统</strong> <time datetime="2025-08-25T22:03:00.000Z">2025/08/26</time> </a><a href="/posts/ce1ec3fe/"> <strong>使用GitHub推送Hexo到服务器</strong> <time datetime="2025-08-18T17:10:18.000Z">2025/08/19</time> </a><a href="/posts/c6143ad3/"> <strong>自定义页脚(新)</strong> <time datetime="2025-08-14T17:05:27.000Z">2025/08/15</time> </a> </div> </section> <section class="sidebar-card site-info-card" data-site-info-card data-stats-endpoint="https://blogumami.biss.click"> <h2><i class="fa-solid fa-chart-line" aria-hidden="true"></i> 网站信息</h2> <dl class="site-info-list"> <div> <dt>文章数目</dt> <dd>43</dd> </div><div> <dt>本站总字数</dt> <dd>32,569</dd> </div><div> <dt>本站访客数</dt> <dd data-stat-key="visitors">--</dd> </div><div> <dt>本站访问量</dt> <dd data-stat-key="pageviews">--</dd> </div><div> <dt>最后更新时间</dt> <dd>2026/06/19</dd> </div> </dl> </section> <script>
(() => {
const cacheDuration = 10 * 60 * 1000;
const formatter = new Intl.NumberFormat('en-US');
const cards = [...document.querySelectorAll('[data-site-info-card]')];
const endpoint = cards.find((card) => card.dataset.statsEndpoint)?.dataset.statsEndpoint;
if (!endpoint) return;
const cacheKey = `site-info-stats:${endpoint}`;
const updateCards = (stats) => {
const visitors = Number(stats?.visitors);
const pageviews = Number(stats?.pageviews);
cards.forEach((card) => {
const visitorsEl = card.querySelector('[data-stat-key="visitors"]');
const pageviewsEl = card.querySelector('[data-stat-key="pageviews"]');
if (visitorsEl && Number.isFinite(visitors)) visitorsEl.textContent = formatter.format(visitors);
if (pageviewsEl && Number.isFinite(pageviews)) pageviewsEl.textContent = formatter.format(pageviews);
});
};
try {
const cached = JSON.parse(localStorage.getItem(cacheKey) || 'null');
if (cached?.time && Date.now() - cached.time < cacheDuration) {
updateCards(cached.data);
return;
}
} catch {
localStorage.removeItem(cacheKey);
}
fetch(endpoint, { headers: { Accept: 'application/json' } })
.then((response) => {
if (!response.ok) throw new Error(`Stats request failed: ${response.status}`);
return response.json();
})
.then((data) => {
localStorage.setItem(cacheKey, JSON.stringify({ time: Date.now(), data }));
updateCards(data);
})
.catch(() => {
});
})();
</script> </div> </aside> </section> </main> <footer class="site-footer" aria-label="站点页脚"> <div class="footer-inner"> <section class="footer-top" aria-label="站点信息"> <a class="footer-brand" href="/" aria-label="Bi's Blog 首页"> <img src="/images/Bi.ico" alt="" loading="lazy"> <span>Bi&#39;s Blog</span> </a> <p class="footer-slogan">好奇心转化为代码的空间。</p> </section> <section class="footer-contact" aria-label="联系方式"> <p>联系方式</p> <div class="footer-socials"> <a href="mailto:bishsh2006@gmail.com" aria-label="发送邮件" title="发送邮件"> <i class="fa-solid fa-envelope" aria-hidden="true"></i> </a><a href="/rss.xml" aria-label="订阅 RSS" title="订阅 RSS"> <i class="fa-solid fa-rss" aria-hidden="true"></i> </a><a href="https://github.com/bishshi" target="_blank" rel="noreferrer" aria-label="GitHub" title="GitHub"> <i class="fa-brands fa-github" aria-hidden="true"></i> </a> </div> <nav class="footer-contact-links" aria-label="页脚链接"> <a href="/archives/">发展历程</a> <span aria-hidden="true">|</span><a href="/privacy/">隐私政策</a> </nav> </section> <section class="footer-bottom" aria-label="版权信息"> <div> <p>© 2025 - 2026 Bi&#39;s Blog</p> <p>blog.biss.click | 内容采用 CC BY-NC-SA 4.0 协议</p> </div> <div class="footer-meta"> <p>本站已运行:<span id="site-runtime">计算中...</span></p> <p> <a href="https://fastly.com/" target="_blank" rel="noreferrer">Fastly</a> <span aria-hidden="true">|</span><a href="https://astro.build/" target="_blank" rel="noreferrer">ASTRO</a> </p> </div> </section> </div> </footer> <aside class="hitokoto-card" aria-label="一言" data-hitokoto-card data-astro-cid-4cgfuthx> <div class="hitokoto-card__head" data-astro-cid-4cgfuthx> <button class="hitokoto-card__toggle" type="button" aria-label="展开一言" aria-expanded="true" title="一言" data-hitokoto-toggle data-astro-cid-4cgfuthx> <i class="fa-solid fa-quote-left" aria-hidden="true" data-astro-cid-4cgfuthx></i> <span data-astro-cid-4cgfuthx>一言</span> </button> <div class="hitokoto-card__actions" data-astro-cid-4cgfuthx> <button class="hitokoto-card__refresh" type="button" aria-label="换一句" title="换一句" data-hitokoto-refresh data-astro-cid-4cgfuthx> <i class="fa-solid fa-rotate" aria-hidden="true" data-astro-cid-4cgfuthx></i> </button> <button class="hitokoto-card__collapse" type="button" aria-label="收起一言" title="收起" data-hitokoto-collapse data-astro-cid-4cgfuthx> <i class="fa-solid fa-chevron-down" aria-hidden="true" data-astro-cid-4cgfuthx></i> </button> </div> </div> <a class="hitokoto-card__text" href="https://hitokoto.cn/" target="_blank" rel="noreferrer" data-hitokoto-text data-astro-cid-4cgfuthx>
获取中...
</a> <p class="hitokoto-card__from" data-hitokoto-from data-astro-cid-4cgfuthx>来自 Hitokoto</p> </aside> <script type="module">(()=>{const o=document.querySelector("[data-hitokoto-card]"),s=o?.querySelector("[data-hitokoto-toggle]"),r=o?.querySelector("[data-hitokoto-text]"),l=o?.querySelector("[data-hitokoto-from]"),k=o?.querySelector("[data-hitokoto-refresh]"),m=o?.querySelector("[data-hitokoto-collapse]");if(!(o instanceof HTMLElement)||!(s instanceof HTMLButtonElement)||!(r instanceof HTMLAnchorElement)||!(l instanceof HTMLElement))return;const g="https://yiyan.biss.click/api?encode=json",u="hitokoto-card-cache",y=360*60*1e3,d={sentence:"生活明朗,万物可爱。",source:"本地缓存",url:"https://hitokoto.cn/"},L=["/","/index.html"].includes(window.location.pathname);function c(t){o.classList.toggle("is-collapsed",!t),s.setAttribute("aria-expanded",String(t)),s.setAttribute("aria-label",t?"收起一言":"展开一言")}function f(){try{const t=localStorage.getItem(u);if(!t)return null;const e=JSON.parse(t);return!e||typeof e.expiresAt!="number"||e.expiresAt<=Date.now()?null:e.data}catch{return null}}function x(t){try{localStorage.setItem(u,JSON.stringify({data:t,expiresAt:Date.now()+y}))}catch{}}function i(t){r.textContent=t.sentence,r.href=t.url||"https://hitokoto.cn/",l.textContent=t.source?`出自 ${t.source}`:"来自 Hitokoto"}async function h({force:t=!1}={}){if(!t){const e=f();if(e){i(e);return}}o.classList.add("is-loading"),r.textContent="获取中...";try{const e=await fetch(g);if(!e.ok)throw new Error(`Hitokoto request failed: ${e.status}`);const n=await e.json(),a=n.hitokoto||n.content||n.sentence||n.text,S=typeof a=="string"&&a.trim()?a.trim():d.sentence,E=typeof n.from=="string"&&n.from.trim()?n.from.trim():"Hitokoto",w=n.uuid?`https://hitokoto.cn/?uuid=${encodeURIComponent(n.uuid)}`:"https://hitokoto.cn/",p={sentence:S,source:E,url:w};x(p),i(p)}catch(e){console.error(e),i(f()||d)}finally{o.classList.remove("is-loading")}}c(L),s.addEventListener("click",()=>{c(o.classList.contains("is-collapsed"))}),k?.addEventListener("click",t=>{t.stopPropagation(),c(!0),h({force:!0})}),m?.addEventListener("click",t=>{t.stopPropagation(),c(!1)}),o.addEventListener("click",t=>{o.classList.contains("is-collapsed")&&(t.target instanceof Element&&t.target.closest("a, button")||c(!0))}),h()})();</script> <div class="custom-context-menu" data-context-menu role="menu" aria-hidden="true"> <div class="context-menu-nav" aria-label="页面导航"> <button type="button" data-context-action="back" aria-label="后退上一页" title="后退上一页"> <i class="fa-solid fa-arrow-left" aria-hidden="true"></i> </button> <button type="button" data-context-action="forward" aria-label="前进下一页" title="前进下一页"> <i class="fa-solid fa-arrow-right" aria-hidden="true"></i> </button> <button type="button" data-context-action="reload" aria-label="刷新页面" title="刷新页面"> <i class="fa-solid fa-rotate-right" aria-hidden="true"></i> </button> <a href="/" aria-label="返回首页" title="返回首页"> <i class="fa-solid fa-house" aria-hidden="true"></i> </a> </div> <div class="context-menu-group" data-selection-group hidden> <button type="button" data-context-action="copy-selection" data-selection-item> <i class="fa-regular fa-copy" aria-hidden="true"></i> <span>复制选中文字</span> </button> <button type="button" data-context-action="search-selection" data-selection-item> <i class="fa-brands fa-microsoft" aria-hidden="true"></i> <span>用 Bing 搜索</span> </button> <button type="button" data-context-action="quote-selection" data-selection-item data-comments-item> <i class="fa-regular fa-comment-dots" aria-hidden="true"></i> <span>引用到评论区</span> </button> </div> <div class="context-menu-group" data-image-group hidden> <button type="button" data-context-action="copy-image"> <i class="fa-regular fa-image" aria-hidden="true"></i> <span>复制图片</span> </button> <button type="button" data-context-action="open-image"> <i class="fa-solid fa-up-right-from-square" aria-hidden="true"></i> <span>新页面打开图片</span> </button> <button type="button" data-context-action="copy-image-url"> <i class="fa-solid fa-link" aria-hidden="true"></i> <span>复制图片地址</span> </button> </div> <div class="context-menu-group"> <a href="/archives/"> <i class="fa-solid fa-box-archive" aria-hidden="true"></i> <span>时间线</span> </a> <a href="/categories/"> <i class="fa-solid fa-folder" aria-hidden="true"></i> <span>分类</span> </a> <a href="/tags/"> <i class="fa-solid fa-hashtag" aria-hidden="true"></i> <span>标签</span> </a> <button type="button" data-context-action="comments" data-comments-item> <i class="fa-regular fa-comment-dots" aria-hidden="true"></i> <span>跳转评论区</span> </button> <button type="button" data-context-action="print"> <i class="fa-solid fa-print" aria-hidden="true"></i> <span>打印页面</span> </button> <a href="/cc/"> <i class="fa-solid fa-circle-info" aria-hidden="true"></i> <span>网站版权</span> </a> </div> </div> <script>
(() => {
const menu = document.querySelector('[data-context-menu]');
if (!menu) return;
const selectionItems = [...menu.querySelectorAll('[data-selection-item]')];
const selectionGroup = menu.querySelector('[data-selection-group]');
const commentsItems = [...menu.querySelectorAll('[data-comments-item]')];
const imageGroup = menu.querySelector('[data-image-group]');
const focusableSelector = 'a[href], button:not([disabled])';
let lastSelectionText = '';
let lastImage = null;
const isNativeContextTarget = (target) =>
target instanceof Element &&
Boolean(target.closest('input, textarea, select, [contenteditable="true"], [contenteditable=""]'));
const getCommentsTarget = () =>
document.querySelector('.twikoo-comments, #twikoo-wrap, #twikoo, .tk-comments-container');
const getSelectionText = () => String(window.getSelection?.() || '').trim();
const getImageTarget = (target) => {
if (!(target instanceof Element)) return null;
const image = target.closest('img');
return image instanceof HTMLImageElement ? image : null;
};
const getImageUrl = () => {
if (!lastImage) return '';
return lastImage.currentSrc || lastImage.src || lastImage.getAttribute('src') || '';
};
const copyText = async (text) => {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(text);
return;
}
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.inset = '0 auto auto -9999px';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
textarea.remove();
};
const setMenuState = () => {
const hasSelection = lastSelectionText.length > 0;
const hasComments = Boolean(getCommentsTarget());
const hasImage = Boolean(getImageUrl());
selectionItems.forEach((item) => {
item.hidden = !hasSelection;
});
if (selectionGroup) selectionGroup.hidden = !hasSelection;
commentsItems.forEach((item) => {
item.hidden = !hasComments || (item.hasAttribute('data-selection-item') && !hasSelection);
});
if (imageGroup) imageGroup.hidden = !hasImage;
};
const closeMenu = () => {
menu.classList.remove('is-open');
menu.setAttribute('aria-hidden', 'true');
};
const openMenu = (x, y) => {
setMenuState();
menu.classList.add('is-open');
menu.setAttribute('aria-hidden', 'false');
const rect = menu.getBoundingClientRect();
const gap = 10;
const left = Math.min(Math.max(gap, x), window.innerWidth - rect.width - gap);
const top = Math.min(Math.max(gap, y), window.innerHeight - rect.height - gap);
menu.style.left = `${left}px`;
menu.style.top = `${top}px`;
};
const jumpToComments = () => {
const target = getCommentsTarget();
target?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
const quoteToComments = () => {
jumpToComments();
window.setTimeout(() => {
const textarea = document.querySelector('#twikoo textarea, .twikoo-comments textarea, .tk-input textarea');
if (!(textarea instanceof HTMLTextAreaElement) || !lastSelectionText) return;
const quote = lastSelectionText
.split(/\r?\n/)
.map((line) => `> ${line}`)
.join('\n');
const current = textarea.value.trim();
textarea.value = current ? `${current}\n\n${quote}\n` : `${quote}\n`;
textarea.dispatchEvent(new Event('input', { bubbles: true }));
textarea.focus();
}, 500);
};
const searchSelection = () => {
if (!lastSelectionText) return;
const url = `https://www.bing.com/search?q=${encodeURIComponent(lastSelectionText)}`;
window.open(url, '_blank', 'noopener,noreferrer');
};
const copyImage = async () => {
const imageUrl = getImageUrl();
if (!imageUrl) return;
try {
if (!navigator.clipboard?.write || typeof ClipboardItem === 'undefined') {
throw new Error('Image clipboard is not available.');
}
const response = await fetch(imageUrl, { mode: 'cors' });
const blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({ [blob.type || 'image/png']: blob }),
]);
} catch {
await copyText(new URL(imageUrl, window.location.href).toString());
}
};
const openImage = () => {
const imageUrl = getImageUrl();
if (!imageUrl) return;
window.open(new URL(imageUrl, window.location.href).toString(), '_blank', 'noopener,noreferrer');
};
document.addEventListener('contextmenu', (event) => {
if (isNativeContextTarget(event.target)) return;
lastSelectionText = getSelectionText();
lastImage = getImageTarget(event.target);
event.preventDefault();
openMenu(event.clientX, event.clientY);
});
document.addEventListener('click', (event) => {
const actionTarget = event.target instanceof Element ? event.target.closest('[data-context-action]') : null;
if (!actionTarget || !menu.contains(actionTarget)) {
closeMenu();
return;
}
const action = actionTarget.dataset.contextAction;
closeMenu();
if (action === 'back') history.back();
if (action === 'forward') history.forward();
if (action === 'reload') location.reload();
if (action === 'copy-selection' && lastSelectionText) copyText(lastSelectionText);
if (action === 'search-selection') searchSelection();
if (action === 'quote-selection') quoteToComments();
if (action === 'copy-image') copyImage();
if (action === 'open-image') openImage();
if (action === 'copy-image-url') copyText(new URL(getImageUrl(), window.location.href).toString());
if (action === 'comments') jumpToComments();
if (action === 'print') window.print();
});
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') closeMenu();
if (event.key === 'Tab' && menu.classList.contains('is-open')) {
const items = [...menu.querySelectorAll(focusableSelector)].filter((item) => !item.closest('[hidden]'));
if (items.length === 0) return;
const first = items[0];
const last = items[items.length - 1];
if (event.shiftKey && document.activeElement === first) {
event.preventDefault();
last.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first.focus();
}
}
});
window.addEventListener('scroll', closeMenu, { passive: true });
window.addEventListener('resize', closeMenu);
})();
</script> <script src="https://cdn.jsdmirror.com/npm/instantsearch.js@4.56.0"></script> <script src="https://cdn.jsdmirror.com/npm/typesense-instantsearch-adapter@2.7.0/dist/typesense-instantsearch-adapter.min.js"></script> <script src="https://cdn.jsdmirror.com/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.umd.js"></script> <script src="/js/random.js"></script> <script src="/js/search/typesense-search.js"></script> <script src="/js/external-links.js"></script> <script>
(() => {
const nav = document.querySelector('.nav');
const toggle = document.querySelector('[data-nav-toggle]');
const menu = document.querySelector('[data-nav-menu]');
if (!nav || !toggle || !menu) return;
function setMenu(open) {
nav.classList.toggle('is-open', open);
toggle.setAttribute('aria-expanded', String(open));
toggle.setAttribute('aria-label', open ? '关闭菜单' : '打开菜单');
}
toggle.addEventListener('click', () => {
setMenu(!nav.classList.contains('is-open'));
});
menu.addEventListener('click', (event) => {
if (event.target instanceof Element && event.target.closest('a')) setMenu(false);
});
window.addEventListener('resize', () => {
if (window.innerWidth > 720) setMenu(false);
});
})();
(() => {
const storageKey = 'site-theme';
const root = document.documentElement;
const button = document.querySelector('[data-theme-toggle]');
const media = window.matchMedia('(prefers-color-scheme: dark)');
const getSystemTheme = () => (media.matches ? 'dark' : 'light');
const getTheme = () => localStorage.getItem(storageKey) || getSystemTheme();
function applyTheme(theme) {
root.dataset.theme = theme;
button?.setAttribute('aria-label', theme === 'dark' ? '切换到日间模式' : '切换到夜间模式');
button?.setAttribute('title', theme === 'dark' ? '切换到日间模式' : '切换到夜间模式');
}
applyTheme(getTheme());
button?.addEventListener('click', () => {
const nextTheme = root.dataset.theme === 'dark' ? 'light' : 'dark';
localStorage.setItem(storageKey, nextTheme);
applyTheme(nextTheme);
});
media.addEventListener('change', () => {
if (!localStorage.getItem(storageKey)) applyTheme(getSystemTheme());
});
})();
(() => {
const runtime = document.getElementById('site-runtime');
if (!runtime) return;
const start = new Date(window.SITE_CONFIG.site.startTime).getTime();
const pad = (value) => String(value).padStart(2, '0');
function updateRuntime() {
const diff = Math.max(0, Date.now() - start);
const days = Math.floor(diff / 86400000);
const hours = Math.floor((diff / 3600000) % 24);
const minutes = Math.floor((diff / 60000) % 60);
const seconds = Math.floor((diff / 1000) % 60);
runtime.textContent = `${days}${pad(hours)}${pad(minutes)}${pad(seconds)} 秒`;
}
updateRuntime();
window.setInterval(updateRuntime, 1000);
})();
</script> </body> </html> <script>
(() => {
const prose = document.querySelector('.prose[data-toc]');
if (!prose) return;
let toc = [];
try {
toc = JSON.parse(prose.dataset.toc || '[]');
} catch {
toc = [];
}
prose.querySelectorAll('h1, h2, h3').forEach((heading, index) => {
const item = toc[index];
if (item?.id && !heading.id) heading.id = item.id;
});
const tocTree = document.querySelector('[data-toc-tree]');
if (tocTree && toc.length > 0) {
const links = [...tocTree.querySelectorAll('[data-toc-link]')];
const groups = [...tocTree.querySelectorAll('[data-toc-group]')];
const headings = toc
.map((item) => document.getElementById(item.id))
.filter(Boolean);
const setActiveToc = (id) => {
links.forEach((link) => {
const isActive = link.getAttribute('href') === `#${id}`;
link.classList.toggle('is-active', isActive);
if (isActive) link.setAttribute('aria-current', 'location');
else link.removeAttribute('aria-current');
});
const activeLink = tocTree.querySelector(`[data-toc-link][href="#${CSS.escape(id)}"]`);
const activeGroup = activeLink?.closest('[data-toc-group]');
groups.forEach((group) => group.classList.toggle('is-open', group === activeGroup));
};
const updateToc = () => {
const anchorOffset = 132;
let activeId = headings[0]?.id;
headings.forEach((heading) => {
if (heading.getBoundingClientRect().top <= anchorOffset) activeId = heading.id;
});
if (activeId) setActiveToc(activeId);
};
tocTree.addEventListener('click', (event) => {
const link = event.target.closest?.('[data-toc-link]');
if (!link) return;
const group = link.closest('[data-toc-group]');
groups.forEach((item) => item.classList.toggle('is-open', item === group));
});
updateToc();
window.addEventListener('scroll', updateToc, { passive: true });
window.addEventListener('resize', updateToc);
}
const summaryText = document.querySelector('.article-summary-text');
if (!summaryText) return;
const fullText = summaryText.dataset.summaryText || summaryText.textContent || '';
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduceMotion) {
summaryText.textContent = fullText;
return;
}
summaryText.textContent = '';
let index = 0;
function typeSummary() {
index += 1;
summaryText.textContent = fullText.slice(0, index);
if (index < fullText.length) {
window.setTimeout(typeSummary, 34);
}
}
window.setTimeout(typeSummary, 280);
})();
</script> <script>
(() => {
const prose = document.querySelector('.post-article .prose');
if (!prose) return;
const collapsedLineCount = 8;
const copyLabels = {
idle: '复制',
done: '已复制',
error: '复制失败',
};
const languageNames = {
bash: 'Bash',
c: 'C',
cpp: 'C++',
cs: 'C#',
css: 'CSS',
html: 'HTML',
js: 'JavaScript',
json: 'JSON',
jsx: 'JSX',
md: 'Markdown',
powershell: 'PowerShell',
py: 'Python',
shell: 'Shell',
sh: 'Shell',
ts: 'TypeScript',
tsx: 'TSX',
txt: 'Text',
yaml: 'YAML',
yml: 'YAML',
};
function getCodeLanguage(pre, code) {
const rawLanguage =
pre.dataset.language ||
code.dataset.language ||
[...pre.classList, ...code.classList]
.find((className) => className.startsWith('language-'))
?.replace(/^language-/, '') ||
'';
const normalized = rawLanguage.trim().toLowerCase();
return languageNames[normalized] || normalized.toUpperCase() || 'Code';
}
function getCodeText(code, lines) {
if (lines.length > 0) return lines.map((line) => line.textContent || '').join('\n');
return code.textContent || '';
}
prose.querySelectorAll('img').forEach((image) => {
if (image.closest('a, .article-header-cover')) return;
const src = image.currentSrc || image.getAttribute('src');
if (!src) return;
const link = document.createElement('a');
link.className = 'fancybox';
link.href = src;
link.dataset.fancybox = 'article-gallery';
link.dataset.caption = image.getAttribute('alt') || '';
image.parentNode?.insertBefore(link, image);
link.appendChild(image);
});
prose.querySelectorAll('table').forEach((table) => {
if (table.closest('.table-scroll')) return;
const wrapper = document.createElement('div');
wrapper.className = 'table-scroll';
table.parentNode?.insertBefore(wrapper, table);
wrapper.appendChild(table);
});
prose.querySelectorAll('.butterfly-hide-inline').forEach((item) => {
const button = item.querySelector('.butterfly-hide-toggle');
if (!button) return;
button.addEventListener('click', () => {
item.classList.toggle('is-open');
});
});
if (window.Fancybox) {
window.Fancybox.bind('[data-fancybox="article-gallery"]', {
compact: false,
dragToClose: true,
Images: {
zoom: true,
},
});
}
async function copyText(text) {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(text);
return;
}
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.top = '-9999px';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
textarea.remove();
}
prose.querySelectorAll('pre').forEach((pre) => {
if (pre.closest('.code-block')) return;
const code = pre.querySelector('code');
if (!code) return;
const wrapper = document.createElement('div');
wrapper.className = 'code-block';
pre.parentNode?.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
const header = document.createElement('div');
header.className = 'code-block-header';
const language = document.createElement('span');
language.className = 'code-block-language';
language.textContent = getCodeLanguage(pre, code);
const toolbar = document.createElement('div');
toolbar.className = 'code-block-toolbar';
const copyButton = document.createElement('button');
copyButton.className = 'code-block-copy';
copyButton.type = 'button';
copyButton.textContent = copyLabels.idle;
copyButton.setAttribute('aria-label', '复制代码');
const toggleButton = document.createElement('button');
toggleButton.className = 'code-block-toggle';
toggleButton.type = 'button';
toggleButton.textContent = '展开';
toggleButton.setAttribute('aria-expanded', 'false');
toolbar.append(copyButton, toggleButton);
header.append(language, toolbar);
wrapper.appendChild(header);
const codeLines = [...code.querySelectorAll(':scope > .line')];
if (codeLines.length > 0) {
wrapper.classList.add('has-line-numbers');
wrapper.style.setProperty('--line-number-width', `${String(codeLines.length).length + 1}ch`);
codeLines.forEach((line, index) => {
line.dataset.line = String(index + 1);
});
}
const lineCount = codeLines.length || (code.textContent || '').split(/\r?\n/).length;
if (lineCount > collapsedLineCount) wrapper.classList.add('is-collapsible');
copyButton.addEventListener('click', async () => {
try {
await copyText(getCodeText(code, codeLines));
copyButton.textContent = copyLabels.done;
window.setTimeout(() => {
copyButton.textContent = copyLabels.idle;
}, 1400);
} catch {
copyButton.textContent = copyLabels.error;
window.setTimeout(() => {
copyButton.textContent = copyLabels.idle;
}, 1600);
}
});
toggleButton.addEventListener('click', () => {
const isExpanded = wrapper.classList.toggle('is-expanded');
toggleButton.textContent = isExpanded ? '收起' : '展开';
toggleButton.setAttribute('aria-expanded', String(isExpanded));
});
});
})();
</script>