You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将复制到剪贴板功能与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">&lt;</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">&gt;</span>
    <span class="support tag"><span class="support tag">&lt;</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">&gt;</span>
      <span class="support tag"><span class="support tag">&lt;</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">&gt;</span>Column 1<span class="support tag"><span class="support tag">&lt;</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">&gt;</span>
      <span class="support tag"><span class="support tag">&lt;</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">&gt;</span>Column 2<span class="support tag"><span class="support tag">&lt;</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">&gt;</span>
      <span class="support tag"><span class="support tag">&lt;</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">&gt;</span>Column 3<span class="support tag"><span class="support tag">&lt;</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">&gt;</span>
    <span class="support tag"><span class="support tag">&lt;</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">&gt;</span>
  <span class="support tag"><span class="support tag">&lt;</span><span class="support tag special">/</span><span class="support tag-name">div</span></span><span class="support tag close">&gt;</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='&lt;div class="container"&gt;
  &lt;div class="row"&gt;
    &lt;div class="col"&gt;Column 1&lt;/div&gt;
    &lt;div class="col"&gt;Column 2&lt;/div&gt;
    &lt;div class="col"&gt;Column 3&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;'>
    <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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 02:31:14