如何使用 JavaScript 复制到剪贴板?

将文本复制到剪贴板的最佳方法是什么? (多浏览器)

我试过了:

function copyToClipboard(text) {
    if (window.clipboardData) { // Internet Explorer
        window.clipboardData.setData("Text", text);
    } else {  
        unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  
        const clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);  
        clipboardHelper.copyString(text);
    }
}

但是在 Internet Explorer 中,它会给出语法错误。在 Firefox 中,它说unsafeWindow is not defined

一个没有闪光灯的好技巧: Trello 如何访问用户的剪贴板?

答案

总览

有三种主要的浏览器 API 可复制到剪贴板:

  1. 异步剪贴板 API [navigator.clipboard.writeText]
    • Chrome 66 中提供了以文本为中心的部分(2018 年 3 月)
    • 访问是异步的,并且使用JavaScript Promises ,可以编写,因此安全用户提示(如果显示)不会中断页面中的 JavaScript。
    • 文本可以直接从变量复制到剪贴板。
    • 仅在通过 HTTPS 服务的页面上受支持。
    • 在 Chrome 66 中,活动标签页中的页面可以写入剪贴板而没有权限提示。
  2. document.execCommand('copy')
    • 截至 2015 年 4 月,大多数浏览器都支持此功能(请参阅下面的浏览器支持)。
    • 访问是同步的,即在页面中停止 JavaScript 直到完成,包括显示和用户与任何安全提示进行交互。
    • 从 DOM 中读取文本并将其放置在剪贴板上。
    • 在 2015 年 4 月〜测试期间,只有 Internet Explorer 被记录为在写入剪贴板时显示权限提示。
  3. 覆盖复制事件
    • 请参阅剪贴板 API 文档中有关覆盖复制事件的信息
    • 允许您通过任何复制事件来修改剪贴板上显示的内容,可以包括除纯文本之外的其他数据格式。
    • 此处未涵盖,因为它不能直接回答问题。

一般发展说明

在控制台中测试代码时,不要期望剪贴板相关的命令能够正常工作。通常,页面需要处于活动状态(异步剪贴板 API)或需要用户交互(例如,用户单击)才能允许( document.execCommand('copy') )访问剪贴板,有关更多详细信息,请参见下文。

异步 + 后备

由于浏览器对新的 Async Clipboard API 的支持水平,您可能希望回退到document.execCommand('copy')方法以获得良好的浏览器覆盖率。

这是一个简单的示例:

function fallbackCopyTextToClipboard(text) {
  var textArea = document.createElement("textarea");
  textArea.value = text;
  textArea.style.position="fixed";  //avoid scrolling to bottom
  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    console.error('Async: Could not copy text: ', err);
  });
}

var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:

  </textarea>
</div>

请注意,此代码段在 Stack Overflow 的嵌入式预览中效果不佳,您可以在这里尝试: https : //codepen.io/DeanMarkTaylor/pen/RMRaJX?editors=1011

异步剪贴板 API

请注意,可以通过 Chrome 66 中的权限 API 来 “请求权限” 并测试对剪贴板的访问权限。

var text = "Example text to appear on clipboard";
navigator.clipboard.writeText(text).then(function() {
  console.log('Async: Copying to clipboard was successful!');
}, function(err) {
  console.error('Async: Could not copy text: ', err);
});

document.execCommand('copy')

本文的其余部分深入介绍document.execCommand('copy') API 的细微差别和细节。

浏览器支持

对 JavaScript document.execCommand('copy')支持已经增长,请参阅下面的链接以获取浏览器更新:

简单的例子

var copyTextareaBtn = document.querySelector('.js-textareacopybtn');

copyTextareaBtn.addEventListener('click', function(event) {
  var copyTextarea = document.querySelector('.js-copytextarea');
  copyTextarea.focus();
  copyTextarea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }
});
<p>
  <button class="js-textareacopybtn" style="vertical-align:top;">Copy Textarea</button>
  <textarea class="js-copytextarea">Hello I'm some text</textarea>
</p>

复杂的示例:复制到剪贴板而不显示输入

如果屏幕上可见textareainput元素,则上面的简单示例非常textarea

在某些情况下,您可能希望将文本复制到剪贴板而不显示input / textarea元素。这是解决此问题的一种方式(基本上是插入元素,复制到剪贴板,删除元素):

已在 Google Chrome 44,Firefox 42.0a1 和 Internet Explorer 11.0.8600.17814 上进行测试。

function copyTextToClipboard(text) {
  var textArea = document.createElement("textarea");

  //
  // *** This styling is an extra step which is likely not required. ***
  //
  // Why is it here? To ensure:
  // 1. the element is able to have focus and selection.
  // 2. if element was to flash render it has minimal visual impact.
  // 3. less flakyness with selection and copying which **might** occur if
  //    the textarea element is not visible.
  //
  // The likelihood is the element won't even render, not even a
  // flash, so some of these are just precautions. However in
  // Internet Explorer the element is visible whilst the popup
  // box asking the user for permission for the web page to
  // copy to the clipboard.
  //

  // Place in top-left corner of screen regardless of scroll position.
  textArea.style.position = 'fixed';
  textArea.style.top = 0;
  textArea.style.left = 0;

  // Ensure it has a small width and height. Setting to 1px / 1em
  // doesn't work as this gives a negative w/h on some browsers.
  textArea.style.width = '2em';
  textArea.style.height = '2em';

  // We don't need padding, reducing the size if it does flash render.
  textArea.style.padding = 0;

  // Clean up any borders.
  textArea.style.border = 'none';
  textArea.style.outline = 'none';
  textArea.style.boxShadow = 'none';

  // Avoid flash of white box if rendered for any reason.
  textArea.style.background = 'transparent';


  textArea.value = text;

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }

  document.body.removeChild(textArea);
}


var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:

  </textarea>
</div>

补充说明

仅在用户采取措施时有效

所有document.execCommand('copy')调用必须直接作为用户操作(例如,单击事件处理程序)的结果而发生。这是一种防止在用户不期望的时候弄乱用户剪贴板的措施。

有关更多信息,请参见此处Google Developers 帖子

剪贴板 API

请注意,完整的 Clipboard API 草案规范可在以下位置找到: https : //w3c.github.io/clipboard-apis/

支持吗?

  • 如果命令 “受浏览器支持”,则document.queryCommandSupported('copy')应返回true
  • 如果document.execCommand('copy')调用成功,则document.queryCommandEnabled('copy')返回true 。检查以确保从用户启动的线程调用了该命令,并且满足其他要求。

但是,作为浏览器兼容性问题的一个示例,如果从用户启动的线程中调用了该命令,则从〜April 到〜October 2015 年的 Google Chrome 仅从document.queryCommandSupported('copy')返回true

请注意下面的兼容性详细信息。

浏览器兼容性详细信息

尽管通过单击用户调用而在try / catch块中包装的document.execCommand('copy')的简单调用将使您获得最大的兼容性,但下面有一些规定:

任何对document.execCommanddocument.queryCommandSupporteddocument.queryCommandEnabled调用都应包装在try / catch块中。

调用时,不同的浏览器实现和浏览器版本会引发不同类型的异常,而不是返回false

各种浏览器实现仍在不断发展,而Clipboard API仍在起草阶段,因此请记住进行测试。

自动复制到剪贴板可能很危险,因此大多数浏览器(IE 除外)都使它非常困难。我个人使用以下简单技巧:

function copyToClipboard(text) {
  window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
}

向用户显示提示框,其中已选择要复制的文本。现在按下Ctrl + C并按Enter (关闭框)就足够了,瞧!

现在,剪贴板复制操作为 SAFE,因为用户手动进行了操作(但以非常简单的方式)。当然,可以在所有浏览器中使用。

<button id="demo" onclick="copyToClipboard(document.getElementById('demo').innerHTML)">This is what I want to copy</button>

<script>
  function copyToClipboard(text) {
    window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
  }
</script>

以下方法适用于 Chrome,Firefox,Internet Explorer 和 Edge,以及最新版本的 Safari(复制支持已添加到 2016 年 10 月发布的版本 10 中)。

  • 创建一个 textarea 并将其内容设置为要复制到剪贴板的文本。
  • 将文本区域附加到 DOM。
  • 在文本区域中选择文本。
  • 调用 document.execCommand(“copy”)
  • 从 dom 中删除文本区域。

注意:您不会看到文本区域,因为它是在同一 Javascript 代码同步调用中添加和删除的。

如果您自己执行此操作,请注意以下事项:

  • 出于安全原因,只能从事件处理程序(如 click)中调用(就像打开窗口一样)。
  • 第一次更新剪贴板时,Internet Explorer 将显示一个权限对话框。
  • Internet Explorer 和 Edge 将在文本区域成为焦点时滚动。
  • execCommand()在某些情况下可能会抛出。
  • 除非使用 textarea,否则换行符和制表符可能会被吞下。 (大多数文章似乎建议使用 div)
  • 显示 Internet Explorer 对话框时,该文本区域将可见,您需要将其隐藏,或使用 Internet Explorer 特定的剪贴板数据 API。
  • 在 Internet Explorer 系统中,管理员可以禁用剪贴板 API。

下面的函数应尽可能清晰地处理以下所有问题。如果发现任何问题或有任何改进建议,请发表评论。

// Copies a string to the clipboard. Must be called from within an
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+,
// Firefox 42+, Safari 10+, Edge and Internet Explorer 10+.
// Internet Explorer: The clipboard feature may be disabled by
// an administrator. By default a prompt is shown the first
// time the clipboard is used (per session).
function copyToClipboard(text) {
    if (window.clipboardData && window.clipboardData.setData) {
        // Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
        return clipboardData.setData("Text", text);

    }
    else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
        var textarea = document.createElement("textarea");
        textarea.textContent = text;
        textarea.style.position = "fixed";  // Prevent scrolling to bottom of page in Microsoft Edge.
        document.body.appendChild(textarea);
        textarea.select();
        try {
            return document.execCommand("copy");  // Security exception may be thrown by some browsers.
        }
        catch (ex) {
            console.warn("Copy to clipboard failed.", ex);
            return false;
        }
        finally {
            document.body.removeChild(textarea);
        }
    }
}

https://jsfiddle.net/fx6a6n6x/

如果您想要一个非常简单的解决方案(集成时间少于 5 分钟)并且看起来开箱即用,那么Clippy是一些更复杂的解决方案的不错选择。

它是由 GitHub 的联合创始人编写的。以下示例 Flash 嵌入代码:

<object
   classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
   width="110"
   height="14"
   id="clippy">
  <param name="movie" value="/flash/clippy.swf"/>
  <param name="allowScriptAccess" value="always"/>
  <param name="quality" value="high"/>
  <param name="scale" value="noscale"/>
  <param NAME="FlashVars" value="text=#{text}"/>
  <param name="bgcolor" value="#{bgcolor}"/>
  <embed
     src="/flash/clippy.swf"
     width="110"
     height="14"
     name="clippy"
     quality="high"
     allowScriptAccess="always"
     type="application/x-shockwave-flash"
     pluginspage="http://www.macromedia.com/go/getflashplayer"
     FlashVars="text=#{text}"
     bgcolor="#{bgcolor}"/>
</object>

请记住将#{text}替换为您需要复制的文本,并将#{bgcolor}替换为颜色。

从网页上读取和修改剪贴板会引发安全性和隐私问题。但是,在 Internet Explorer 中可以这样做。我发现了这个示例片段

<script type="text/javascript">
        function select_all(obj) {
            var text_val=eval(obj);
            text_val.focus();
            text_val.select();
            r = text_val.createTextRange();
            if (!r.execCommand) return; // feature detection
            r.execCommand('copy');
        }
    </script>
    <input value="http://www.sajithmr.com"
     onclick="select_all(this)" name="url" type="text" />

我最近写了一篇有关此问题的技术博客文章 (我在 Lucidchart 工作,最近我们对剪贴板进行了大修)。

假设您要在系统复制事件(用户按下Ctrl C或使用浏览器的菜单)期间执行此操作,将纯文本复制到剪贴板相对简单。

var isIe = (navigator.userAgent.toLowerCase().indexOf("msie") != -1 
           || navigator.userAgent.toLowerCase().indexOf("trident") != -1);

document.addEventListener('copy', function(e) {
    var textToPutOnClipboard = "This is some text";
    if (isIe) {
        window.clipboardData.setData('Text', textToPutOnClipboard);    
    } else {
        e.clipboardData.setData('text/plain', textToPutOnClipboard);
    }
    e.preventDefault();
});

不在系统复制事件期间将文本放在剪贴板上要困难得多。看起来其中一些其他答案引用了通过 Flash 进行操作的方法,这是唯一的跨浏览器方法(据我所知)。

除此之外,还有基于浏览器的一些选项。

这是 IE 中最简单的方法,您可以随时通过以下方式从 JavaScript 访问剪贴板数据对象:

window.clipboardData

(但是,当您尝试在系统剪切,复制或粘贴事件之外执行此操作时,IE 会提示用户授予 Web 应用程序剪贴板权限。)

在 Chrome 中,您可以创建一个 Chrome 扩展程序,该扩展程序将为您提供剪贴板权限 (这是我们对 Lucidchart 所做的工作)。然后,对于安装了扩展程序的用户,您只需要自己触发系统事件即可:

document.execCommand('copy');

Firefox 似乎有一些选项 ,允许用户向某些站点授予访问剪贴板的权限,但是我个人没有尝试过这些选项。

这是我对此的看法...

function copy(text) {
    var input = document.createElement('input');
    input.setAttribute('value', text);
    document.body.appendChild(input);
    input.select();
    var result = document.execCommand('copy');
    document.body.removeChild(input);
    return result;
 }

剪贴板. js是一个小型的非 Flash 实用程序,允许将文本或 HTML 数据复制到剪贴板。它非常易于使用,只需包含. js 并使用如下代码:

<button id='markup-copy'>Copy Button</button>

<script>
document.getElementById('markup-copy').addEventListener('click', function() {
  clipboard.copy({
    'text/plain': 'Markup text. Paste me into a rich text editor.',
    'text/html': '<i>here</i> is some <b>rich text</b>'
  }).then(
    function(){console.log('success'); },
    function(err){console.log('failure', err);
  });

});
</script>

Clipboard.js 也位于GitHub 上

注意:现在不建议使用。迁移到这里

ZeroClipboard 是我发现的最好的跨浏览器解决方案:

<div id="copy" data-clipboard-text="Copy Me!">Click to copy</div>    
<script src="ZeroClipboard.js"></script>
<script>
  var clip = new ZeroClipboard( document.getElementById('copy') );
</script>

如果您需要 iOS 的非 Flash 支持,则只需添加一个备用:

clip.on( 'noflash', function ( client, args ) {
    $("#copy").click(function(){            
        var txt = $(this).attr('data-clipboard-text');
        prompt ("Copy link, then click OK.", txt);
    });
});

http://zeroclipboard.org/

https://github.com/zeroclipboard/ZeroClipboard

在我正在从事的项目之一中,一个使用零剪贴板库的 jQuery 复制到剪贴板插件。

如果您是大量 jQuery 用户,则它比本机 “零剪贴板” 插件更易于使用。