题 如何使用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

没有flash的好技巧: Trello如何访问用户的剪贴板?


2670
2017-12-30 13:09


起源


没什么特别的。他们可以自己做,但我想提供点击按钮的可能性,而不用担心选择正确的文本部分。 - Santiago Corredoira
可能重复 使用FireFox,Safari和Chrome将文本放在剪贴板上 - GvS
这篇长博文包含了很多方法: 使用JavaScript访问系统剪贴板 - 圣杯? - Aaron Digulla
它在IE和FF中提供浏览器未定义的异常 - Jagadeesh
如果我们可以将文本放入用户的剪贴板中,我们就会破坏他的剪贴板。 - Frank Fang


答案:


概观

有3个主要的浏览器API可用于复制到剪贴板:

  1. 异步剪贴板API  [navigator.clipboard.writeText]
    • 以文本为重点的部分 Chrome 66(2018年3月)
    • 访问是异步和使用 JavaScript承诺,可以编写安全用户提示(如果显示)不中断页面中的JavaScript。
    • 可以直接从变量将文本复制到剪贴板。
    • 仅在通过HTTPS提供的页面上受支持。
    • 在Chrome中,活动标签中的66页可以在没有权限提示的情况下写入剪贴板。
  2. document.execCommand('copy')
    • 大多数浏览器都支持2015年4月〜(请参阅下面的浏览器支持)。
    • 访问是同步的,即在页面中停止JavaScript直到完成,包括显示和用户与任何安全提示交互。
    • 从DOM读取文本并将其放在剪贴板上。
    • 在测试期间〜2015年4月,只有Internet Explorer被注意为在写入剪贴板时显示权限提示。
  3. 覆盖复制事件
    • 请参阅剪贴板API文档 覆盖复制事件
    • 允许您修改任何复制事件在剪贴板上显示的内容,可以包括纯文本以外的其他格式的数据。
    • 这里没有涉及,因为它没有直接回答这个问题。

一般发展说明

在控制台中测试代码时,不要指望与剪贴板相关的命令可以正常工作。通常,页面必须是活动的(Async Clipboard API)或需要用户交互(例如用户点击)才能允许(document.execCommand('copy'))访问剪贴板请参阅下面的详细信息。

异步+后备

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

这是一个简单的例子:

function fallbackCopyTextToClipboard(text) {
  var textArea = document.createElement("textarea");
  textArea.value = text;
  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>

请注意,此片段在StackOverflow的嵌入式预览中效果不佳,您可以在此处尝试: 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( '复制')

这篇文章的其余部分涉及到的细微差别和细节 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>

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

如果有一个,上面这个简单的例子很有用 textarea 要么 input 元素在屏幕上可见。

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

使用Google Chrome 44,Firefox 42.0a1和IE 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 IE 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.queryCommandEnabled('copy') 返回 true 如果 document.execCommand('copy') 如果现在打电话会成功。检查以确保从用户启动的线程调用该命令并满足其他要求。

但是,作为浏览器兼容性问题的一个示例,Google Chrome从2015年4月到10月才返回 true 从 document.queryCommandSupported('copy') 如果从用户启动的线程调用该命令。

请注意以下兼容性细节

浏览器兼容性细节

虽然简单的电话 document.execCommand('copy') 裹着一个 try/catch 由于用户点击而调用的块将获得最大的兼容性使用以下有一些附带条件:

任何电话 document.execCommanddocument.queryCommandSupported 要么 document.queryCommandEnabled 应该包裹在一个 try/catch 块。

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

不同的浏览器实现仍在不断变化 剪贴板API 还在吃水,所以记得做你的测试。


1593
2018-06-12 18:56



如何直接从变量数据中复制.i.e。: var str = "word"; ? - jscripter
@BubuDaba创建一个虚拟隐藏 <textarea> 使用JS,将其附加到 document.body,将其值设置为变量,并以其速度使用它 copyTextarea,然后在复制内容后立即删除它。 - SeinopSys
Safari或其他任何指标都可以在Safari中实现吗? - www139
@AyaSalama的关键点在于,除非用户正在采取操作的浏览器出现,否则无法进行“复制”操作。如果元素使用“display:none”设置样式,则用户将无法执行操作,因为他们无法看到它,也无法与之交互。 - Dean Taylor
这适用于任何人的iPhone Safari吗? - SB2055


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

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

将向用户显示提示框,其中已选择要复制的文本。现在它足以按下了 按Ctrl+C 和 输入 (关闭盒子) - 瞧!

现在剪贴板复制操作是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>


1195
2018-05-19 08:06



不错的诀窍 - 但请记住它是适用于Mac的Cmd-C - Casebash
聪明,但这只支持单行。 - Aram Kocharyan
将“提示”功能更改为自定义模式是微不足道的,其诀窍在于使用可编辑的内容字段并预先选择文本,并且通过强制用户执行以下操作不会破坏浏览器UI行动本身。 A ++ - Jon z
仍然没有使用javascript复制到剪贴板^ _ ^ - RozzA
奇怪的是,当它没有回答这个问题时,这会得到457个upvotes:复制到剪贴板 在Javascript中! - stevenvh


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

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

注意:您将看不到textarea,因为它是在Javascript代码的同一个同步调用中添加和删除的。

如果您自己实现这一点,需要注意的一些事项:

  • 出于安全原因,这只能从事件处理程序(如click)调用(就像打开窗口一样)。
  • IE将在第一次更新剪贴板时显示权限对话框。
  • IE和Edge将在textarea聚焦时滚动。
  • execCommand()可能会抛出某些情况。
  • 除非您使用textarea,否则可能会吞下新行和制表符。 (大多数文章似乎建议使用div)
  • 显示IE对话框时,textarea将可见,您需要隐藏它,或使用IE特定的clipboardData api。
  • 在IE系统中,管理员可以禁用剪贴板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 IE 10+.
// IE: 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) {
        // IE 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 MS 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/


196
2017-11-26 00:03



很好的答案:跨浏览器支持,错误处理+清理。截至今天对queryCommandSupported的新支持,现在可以在Javascript中复制到剪贴板,这应该是接受的答案,而不是尴尬的'window.prompt(“复制到剪贴板:Ctrl + C,输入”,文本)'解决方法。 IE9中支持window.clipboardData,所以你应该在浏览器支持列表中添加IE9,我想也许IE8和之前也有,但需要验证。 - user627283
是啊。 IE 8/9应该没问题。我们的应用程序不支持它们。所以我没有测试过。 IE在1月停止了支持,所以我不太讨厌。希望Safari支持很快就会落地。我确信这是他们的雷达。 - Greg Lowe
@SantiagoCorredoira:2016年,这应该是公认的答案。请考虑重新分配BGT(大绿色勾号)。 - Lawrence Dol
@Noitidart我经过测试,它适用于firefox 54,chrome 60和边缘浏览器,即使焦点不在html文档中,你所遇到的错误可能是特定于版本FF 55 - Tosin John
@Noitidart它仍然可以在这里完美运行,专注于开发工具并没有阻止它。顺便说一下,普通的Web应用程序用户将如何处理开发人员工具 - Tosin John


如果你想要一个非常简单的解决方案(整合时间不到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} 有颜色。


93
2017-10-17 14:40



对于任何感兴趣的人,请在复制repo的URL时检查在GitHub上使用的Clippy。 - Radek
仅供参考,在GitHub上使用Clippy已被ZeroClipboard取代。 - James M. Greene
OP想要一个JavaScript解决方案。不闪光。 - MT.
@MT,“javascript”有些人的意思是“在浏览器客户端”,所以虽然只有JS可能是一个要求,许多有机会得到这个答案的人真的在寻找JS或其他广泛支持的人 - 客户端的高科技。 Flash并没有打到所有平台,但是对于像剪贴板支持这样的抛光功能,如果它通过弹出对话框改进了UX(它当然可以),那么值得添加。 - Dave Dopson
现在依靠Flash意味着让一些百分比的网站访问者无法工作,几乎每个人都在做网络开发是不可接受的。 - jinglesthula


从网页读取和修改剪贴板会引起安全和隐私问题。但是,在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" />


78
2017-12-30 13:33



使用flash进行简单的复制操作似乎有点矫枉过正,很高兴有一个干净的JS方法来做到这一点。因为我们在公司环境中。 IE就好了。谢谢Bandi! - Eddie
请问解释一下 execCommand(\\’copy\\’); 如果没有复制到剪贴板的IE? @mrBorna - RozzA
在IE7-IE9中工作正常,谢谢! - luschn
不使用 if(!document.all) 但 if(!r.execCommand) 以免任何人实施它! Document.all绝对与此无关。 - m93a
男人,这就是我喜欢简单干净的代码,它几乎可以永久地进行维护。这对我来说,它工作得很漂亮。 - Samuel Ramzan


我最近写过一篇 技术博客文章 关于这个问题(我在Lucidchart工作,我们最近在剪贴板上进行了大修)。

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

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访问clipboardData对象:

window.clipboardData

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

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

document.execCommand('copy');

它看起来像Firefox 一些选择 允许用户授予某些网站访问剪贴板的权限,但我没有亲自尝试过这些。


65
2017-12-03 20:31



博客文章中没有提到(我希望在不久的将来更新它),是能够使用execCommand触发剪切和复制。 IE10 +,Chrome 43+和Opera29 +支持此功能。在这里阅读它。 updates.html5rocks.com/2015/04/cut-and-copy-commands - Richard Shurtz
这样做的一个问题是它劫持了其他正常的复制事件。 - Brock Adams


clipboard.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上


44
2017-08-11 15:33



该文件库由angular.io用于其英雄之旅,并通过显示用户刚要复制的预选文本,在浏览器不支持execCommand的优雅模式中回退。 - John-Philip


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


35
2017-11-21 20:41



与Flash交叉浏览?不适用于iOS和Android 4.4 - Raptor
查看更新的答案。这样可以减少闪存用户的步骤,并为其他人提供支持。 - Justin
它有十亿行代码。这绝对是嘲笑。最好不要在项目中包含这样的怪物 - vsync
有一个简单的版本 gist.github.com/JamesMGreene/8698897 这是20K,在74k版本中没有所有的花里胡哨。两者都不是很大。我的猜测是大多数用户都可以使用74k或20k文件下载所需的额外毫秒数,因此复制/粘贴只需一次点击而不是两次。 - Justin
@Justin我无法让它在本地工作,即使我复制并粘贴示例(我做了最小的更改,例如 src 在脚本标签中)。我觉得他们的文档很漂亮但效率很低。 - Gui Imamura


这是我对那一个的看法..

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;
 }

30
2017-09-14 09:20



第一次尝试。干杯。 - JustAGuy
很高兴听到我的帮助。 - nikksan
像魅力一样工作,感谢您的帮助。 +1 - FONGOH MARTIN
@nikksan如何复制字符串 \n? - sof-03
在Win10x64上的Microsoft Edge 42.17134.1.0中不起作用 - Honsa Stunna