如何将复制到剪贴板功能与Rainbow语法高亮工具集成
如何将剪贴板复制功能与Rainbow语法高亮库集成
我正尝试把基础的「复制到剪贴板」功能和Rainbow语法高亮库结合,让页面上每个代码片段高亮后,能通过点击「Copy」按钮复制到剪贴板。复制按钮是常用功能,不想用额外插件。我试了下面的Clipboard API脚本,单独运行正常,但和Rainbow一起用的时候复制功能失效,控制台也没报错。有人能帮忙把这个脚本和Rainbow集成吗?
原始HTML示例
<pre class="lang-html" tabindex="0"><code data-language="html"> <div class="container"> <div class="row"> <div class="col">Column 1</div> <div class="col">Column 2</div> <div class="col">Column 3</div> </div> </div> </code></pre>
Rainbow处理后的HTML输出示例
<pre class="lang-html rainbow-show" tabindex="0" data-trimmed="true"><code data-language="html" class="rainbow rainbow-show"> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">div</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">container</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">div</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">row</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">div</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">col</span><span class="string quote">"</span><span class="support tag close">></span>Column 1<span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">div</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">col</span><span class="string quote">"</span><span class="support tag close">></span>Column 2<span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">div</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">col</span><span class="string quote">"</span><span class="support tag close">></span>Column 3<span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">></span> </code><button class="btn btn-secondary2">Copy</button><div class="preloader"><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div></pre>
复制到剪贴板脚本
const copyButtonLabel = "Copy"; // use a class selector if available let blocks = document.querySelectorAll("pre.lang-html"); blocks.forEach((block) => { // only add button if browser supports Clipboard API if (navigator.clipboard) { let button = document.createElement("button"); $(button).addClass( "btn btn-secondary2" ); button.innerText = copyButtonLabel; block.appendChild(button); button.addEventListener("click", async () => { await copyCode(block, button); }); } }); async function copyCode(block, button) { let code = block.querySelector("code"); let text = code.innerText; await navigator.clipboard.writeText(text); // visual feedback that task is completed button.innerText = "Copied"; setTimeout(() => { button.innerText = copyButtonLabel; }, 700); }
解决方案
问题核心是Rainbow会修改<code>标签的DOM结构,且你的脚本可能在Rainbow完成渲染前就执行,导致绑定逻辑失效。以下是修正后的集成方案:
1. 核心修改点
- 监听Rainbow的
rainbow.color事件,确保在所有代码高亮完成后再绑定复制按钮 - 缓存原始代码文本,避免从拆分后的
<span>标签中提取出现格式错误
2. 完整集成脚本
const copyButtonLabel = "Copy"; // 等待Rainbow完成所有代码高亮渲染 document.addEventListener('rainbow.color', function() { const blocks = document.querySelectorAll("pre.lang-html"); blocks.forEach(block => { if (!navigator.clipboard) return; // 避免重复添加按钮 if (block.querySelector('.btn-secondary2')) return; const button = document.createElement("button"); button.classList.add("btn", "btn-secondary2"); button.innerText = copyButtonLabel; block.appendChild(button); // 获取原始代码:优先用预存的data-original,否则用Rainbow处理前的文本 const codeElement = block.querySelector("code"); const originalCode = codeElement.dataset.original || codeElement.textContent.trim(); button.addEventListener("click", async () => { await navigator.clipboard.writeText(originalCode); button.innerText = "Copied"; setTimeout(() => button.innerText = copyButtonLabel, 700); }); }); }); // 手动触发Rainbow高亮(若页面未自动执行) Rainbow.color();
3. 优化原始HTML(可选)
提前给<code>标签添加data-original属性,确保复制内容完全匹配原始代码:
<pre class="lang-html" tabindex="0"> <code data-language="html" data-original='<div class="container"> <div class="row"> <div class="col">Column 1</div> <div class="col">Column 2</div> <div class="col">Column 3</div> </div> </div>'> <div class="container"> <div class="row"> <div class="col">Column 1</div> <div class="col">Column 2</div> <div class="col">Column 3</div> </div> </div> </code> </pre>
内容的提问来源于stack exchange,提问作者jottin
相关产品推荐
相关产品推荐

