默认情况下,Typecho 的代码块不带复制功能,读者需要手动框选文字才能复制代码,体验较差。本文介绍一种纯前端方案——通过注入一段轻量级 JavaScript,在每个代码块右上角自动渲染”复制代码”按钮,无需安装插件,兼容大多数 Typecho 主题。
实现方式:纯 JavaScript + 动态注入 CSS,无外部依赖
适用场景:Typecho 博客,支持任意主题
一、注入脚本
1.1 选择注入位置
根据你使用的主题,选择以下任一方式将脚本添加到页面的 <head> 区域:
方式 A:直接编辑主题文件
找到主题目录下的 header.php,在 </head> 标签之前粘贴脚本代码。
方式 B:通过后台管理面板注入(推荐)
依次进入:控制台 → 外观 → 设置外观 → 主题自定义扩展
将代码粘贴到:
自定义 HTML 元素拓展 → 标签: head 头部(meta 元素后)
后台注入方式无需改动主题文件,升级主题时不会丢失配置,推荐优先使用。
1.2 完整脚本代码
将以下完整代码片段粘贴到上述位置:
<script> // 在代码块右上角添加复制按钮 document.addEventListener('DOMContentLoaded', initCodeCopyButton);
function initCodeCopyButton() {
// 动态注入按钮样式 function initCSS(callback) { const css = ` .btn-code-copy { position: absolute; line-height: .6em; top: .5em; right: .8em; color: rgb(0, 205, 102); font: menu; } .btn-code-copy:hover { color: rgb(145, 145, 145); cursor: pointer; } `; const styleId = btoa('btn-code-copy').replace(/[=+\/]/g, ''); const head = document.getElementsByTagName('head')[0]; if (!head.querySelector('#' + styleId)) { const style = document.createElement('style'); style.id = styleId; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } callback(); }
// 执行复制操作(兼容旧版浏览器) function copyTextContent(source) { let result = false; const target = document.createElement('pre'); target.style.opacity = '0'; target.textContent = source.textContent; document.body.appendChild(target); try { const range = document.createRange(); range.selectNode(target); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); document.execCommand('copy'); window.getSelection().removeAllRanges(); result = true; } catch (e) { console.log('copy failed.'); } document.body.removeChild(target); return result; }
// 为单个 <pre> 元素添加复制按钮 function initButton(pre) { const code = pre.querySelector('code'); if (code) { const preParent = pre.parentElement; const newPreParent = document.createElement('div'); newPreParent.style = 'position: relative'; preParent.insertBefore(newPreParent, pre); const copyBtn = document.createElement('div'); copyBtn.innerHTML = '复制代码'; copyBtn.className = 'btn-code-copy'; copyBtn.addEventListener('click', () => { copyBtn.innerHTML = copyTextContent(code) ? '已复制' : '无法复制'; setTimeout(() => copyBtn.innerHTML = '复制代码', 250); }); newPreParent.appendChild(copyBtn); newPreParent.appendChild(pre); } }
// 查找页面中所有代码块并初始化 const pres = document.querySelectorAll('pre'); if (pres.length !== 0) { initCSS(() => pres.forEach(pre => initButton(pre))); } }</script>1.3 脚本工作原理
脚本由三个核心函数组成,在页面加载完成后自动执行:
函数说明
| 函数 | 作用 |
|---|---|
initCSS() | 动态生成并注入按钮的 CSS 样式,通过唯一 ID 防止重复插入 |
copyTextContent() | 执行复制操作,兼容不支持 Clipboard API 的旧版浏览器 |
initButton() | 遍历页面中所有 <pre> 元素,为含有 <code> 子元素的代码块挂载按钮 |
按钮默认样式
| 样式属性 | 默认值 | 说明 |
|---|---|---|
| 正常颜色 | rgb(0, 205, 102) | 绿色,与常见代码主题搭配 |
| 悬停颜色 | rgb(145, 145, 145) | 灰色,提示可交互 |
| 位置 | 右上角(top: .5em; right: .8em) | 相对于代码块定位 |
| 反馈文案 | 复制代码 → 已复制 → 复制代码 | 点击后 250ms 内恢复原始文案 |
💡 自定义样式:如需调整按钮颜色或位置,修改脚本中
initCSS()函数内的css字符串即可,无需改动其他逻辑。
二、PJAX 兼容处理
2.1 为什么需要额外处理
如果你的主题开启了 PJAX(无刷新页面跳转),在用户点击链接切换页面时,浏览器不会触发完整的页面加载事件,导致 DOMContentLoaded 不再执行,新页面的代码块将不会自动挂载复制按钮。
2.2 配置 PJAX 回调
依次进入:控制台 → 外观 → 设置外观 → PJAX (BETA) → PJAX RELOAD
在回调列表中加入以下一行:
initCodeCopyButton();这样每次 PJAX 完成页面切换后,都会重新执行初始化函数,确保新加载的代码块正常显示复制按钮。
⚠️ 注意:
initCodeCopyButton函数需要在全局作用域中可访问,即脚本不能被包裹在立即执行函数(IIFE)内。上方提供的代码已满足此要求。
参考资料
- 为 Typecho 代码块添加复制按钮 — logi.im↗
- Document.execCommand() — MDN Web Docs↗(已废弃但在旧版浏览器中仍广泛使用)
- Clipboard API — MDN Web Docs↗(现代浏览器推荐方案)
