如何在JavaScript中复制到剪贴板上?

回答 27 浏览 280.9万 2008-12-30

如何将文本复制到剪贴板上(多浏览器)?

相关的: Trello如何访问用户的剪贴板?

Santiago Corredoira 提问于2008-12-30
这仍然不是完美的支持。你可以在我可以使用剪贴板API上看到支持,其中详细说明了对W3C剪贴板API文档的支持。mkobit 2015-04-28
27 个回答
#1楼 已采纳
得票数 3374

概述

有三个主要的浏览器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. 重写复制事件

    • 请参阅关于覆盖复制事件的Clipboard API文档。
    • 允许你修改从任何复制事件中出现在剪贴板上的内容,可以包括除纯文本以外的其他格式的数据。
    • 这里不涉及,因为它没有直接回答这个问题。

一般开发说明

当你在控制台中测试代码时,不要指望与剪贴板有关的命令会工作。一般来说,页面需要被激活(Async Clipboard API)或需要用户互动(如用户点击)以允许(document.execCommand('copy'))访问剪贴板,更多细节见下文。

重要(在此指出2020/02/20)。

请注意,自本帖最初撰写以来,跨源IFRAME中权限的取消和其他IFRAME "沙盒化"使嵌入式演示"运行代码片段" 按钮和"codepen.io 示例"无法在某些浏览器(包括 Chrome 和 Microsoft Edge)中正常工作。

要开发创建你自己的网页,通过HTTPS连接提供该网页,以进行测试和开发。

下面是一个演示代码工作的测试/演示页面:https://deanmarktaylor.github.io/clipboard-test/

异步+回退

由于浏览器对新的异步剪贴板API的支持程度,你很可能想退回到document.execCommand('copy')方法,以获得良好的浏览器覆盖率。

下面是一个简单的例子(嵌入本网站可能无法使用,请阅读上面的"重要"说明):

function fallbackCopyTextToClipboard(text) {
  var textArea = document.createElement("textarea");
  textArea.value = text;
  
  // Avoid scrolling to bottom
  textArea.style.top = "0";
  textArea.style.left = "0";
  textArea.style.position = "fixed";

  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>

(codepen.io的例子可能不起作用,请阅读上面的"重要"说明)注意,这个片段在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('复制')

这篇文章的其余部分将深入探讨document.execCommand('copy') API的细微差别和细节。

浏览器的支持

对JavaScript document.execCommand('copy')的支持已经增加,请看下面的浏览器更新链接:(deprecated) 👎

简单的例子

(可能无法嵌入本网站,请阅读上面的"重要"说明)

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元素是可见的,上述的简单例子就很好用。

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

使用谷歌浏览器44、火狐浏览器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 the 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 the 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 the 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 开发人员的帖子,以了解更多信息。

剪贴板应用程序接口

注意完整的剪贴板API规范草案可以在这里找到:https://w3c.github.io/clipboard-apis/

它是否得到支持?

  • 如果该命令被浏览器支持,则document.queryCommandSupported('copy')应返回true
  • document.queryCommandEnabled('copy')返回true,如果现在调用document.execCommand('copy')会成功。检查以确保该命令是从用户发起的线程中调用的,并满足其他要求。

然而,作为浏览器兼容性问题的一个例子,谷歌浏览器从~2015年4月到~10月,如果命令是从用户发起的线程中调用的,则只返回true,而不是document.queryCommandSupported('copy')

请注意下面的兼容性细节。

浏览器兼容性详解

虽然一个简单的调用document.execCommand('copy')包裹在用户点击后调用的try/catch块中,会让你获得最大的兼容性使用,但下面有一些限制条件:

任何对document.execCommanddocument.queryCommandSupporteddocument.queryCommandEnabled的调用都应该被包裹在一个try/catch的块中。

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

不同的浏览器实现仍在不断变化,并且Clipboard API仍在起草中,所以记得要进行测试。

Dean Taylor 提问于2015-06-12
benhatsor 修改于2021-08-30
对不起,打破了这个聚会 ,但document.execCommand is obsolete。见developer.mozilla.org/en-US/docs/Web/API/Document/execCommandtnkh 2020-10-12
@tnkh 当然,但替代物(剪贴板API)还没有完全出炉,也没有得到支持。forresto 2021-05-03
剪贴板API支持率目前为全球用户的91%:caniuse.com/mdn-api_clipboard_writetextforresthopkinsa 2021-07-29
我只是在回退后添加了焦点的重置:var previousFocusElement = document.activeElement (....all the fallback code...) previousFocusElement.focus();Matthias 2021-10-20
这是一个很好的、彻底的答案--简而言之,使用这个答案中Async + Fallback标题下描述的方法--这实际上是Stackoverflow自己使用的方法!请看这个答案的参考jbyrd 2022-01-20
#2楼
得票数 1370

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

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

用户会看到一个提示框,其中要复制的文本已经被选中。现在只需按下Ctrl+CEnter(关闭提示框)--就可以了!

现在,剪贴板复制操作是安全的,因为用户是手动操作的(但方式很直接)。当然,它在所有的浏览器中都能工作。

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

Jarek Milewski 提问于2011-05-19
Josh Correia 修改于2023-02-01
但该对话框中显示的字符数是有限制的,因此复制的数据量也是有限制的。Denilson Sá Maia 2011-09-04
聪明,但这只支持单行。Aram Kocharyan 2011-10-23
将"提示"功能改为自定义模式是很容易的,关键是要使用一个可编辑的内容字段并预选文本,而且不能因为强制要求用户自己采取行动而破坏浏览器的用户界面。A++Jon z 2012-01-17
如果你的文本超过2000个字符,它将被截断,但对于较小的文本样本,它工作得很好。RasTheDestroyer 2013-09-04
@RasTheDestroyer - 2千字的截断似乎是Chrome浏览器的问题,但不管怎样,知道这一点是很好的。Marcus Pope 2013-09-18
#3楼
得票数 514

以下方法在Chrome、Firefox、Internet Explorer和Edge,以及最近版本的Safari中都可以使用(2016年10月发布的第10版中加入了复制支持)。

  • 创建一个textarea,并将其内容设置为你想复制到剪贴板的文本。
  • 将文本区追加到DOM中。
  • 选择文本区中的文本。
  • 调用document.execCommand("copy")。
  • 从dom中删除textarea。

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

如果你自己实施的话,有一些事情需要注意:

  • 出于安全考虑,这只能从一个事件处理程序中调用,如点击(就像打开窗口一样)。
  • 在第一次更新剪贴板时,Internet Explorer会显示一个权限对话框。
  • Internet Explorer和Edge会在文本区被聚焦时进行滚动。
  • execCommand()在某些情况下可能会被抛出。
  • 除非你使用一个文本区域,否则换行符和制表符会被吞噬。(大多数文章似乎都建议使用div)。
  • 当Internet Explorer对话框显示时,文本区域将是可见的,你要么需要隐藏它,要么使用Internet Explorer特定的clipboardData 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 window.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 prompt("Copy to clipboard: Ctrl+C, Enter", text);
        }
        finally {
            document.body.removeChild(textarea);
        }
    }
}

https://jsfiddle.net/fx6a6n6x/

Greg Lowe 提问于2015-11-26
Jack G 修改于2021-12-17
不错的答案:跨浏览器支持,错误处理+清理。从今天对queryCommandSupported的新支持来看,复制到剪贴板现在在Javascript中是可行的,这应该是公认的答案,而不是尴尬的'window.prompt("Copy to clipboard: Ctrl+C, Enter", text)'工作方法。 window.clipboardData在IE9中被支持,所以你应该在浏览器支持列表中加入IE9,我想也许IE8和以前也是,但是需要验证。user627283 2015-12-01
@SantiagoCorredoira:在2016年,这理应成为公认的答案。请考虑重新分配BGT(大绿勾)。Lawrence Dol 2016-04-22
@Noitidart 我测试了一下,它在firefox 54、chrome 60和edge浏览器上都能完美运行,即使焦点不在html文档中,你遇到的错误可能是FF 55版本的特有错误。Tosin John 2017-08-12
@Noitidart 它在这里仍然工作得很好,专注于开发工具并没有阻止它。顺便说一句,一个普通的网络应用程序用户会在开发工具上做什么呢?Tosin John 2017-08-12
jQuery UI用户:请注意,如果你试图在一个模态对话框中使用这个函数,你会遇到这个方法的问题。我怀疑这是因为jQuery UI模态正在管理/操纵文档焦点。如果这符合你的使用情况,一个解决方法是先关闭模态对话框,然后再复制文本。或者,简单地使用一个非模态对话框。我想你也可以修改这个函数,使它把文本区添加到模态中,而不是添加到正文中。rinogo 2018-12-31
#4楼
得票数 172

这是我对这个问题的看法......

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

@korayem:请注意,使用html input字段不会尊重换行符\n,会把任何文本平铺成单行。

正如@nikksan在评论中提到的那样,使用textarea可以解决如下问题:

function copy(text) {
    var input = document.createElement('textarea');
    input.innerHTML = text;
    document.body.appendChild(input);
    input.select();
    var result = document.execCommand('copy');
    document.body.removeChild(input);
    return result;
}
nikksan 提问于2017-09-14
Korayem 修改于2020-02-17
在Win10x64的Microsoft Edge 42.17134.1.0中不工作。Honsa Stunna 2018-05-30
由于某些原因,我通常的"创建一个隐藏的输入或文本区域,然后选择它并执行Command"并不奏效,而这是迄今为止这里列出的最好的解决方案,尽管其他的解决方案很全面,就像完整的维基百科页面一样,这个方案对我来说很有效,所以+1。Justin 2021-01-31
#5楼
得票数 100

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

bandi 提问于2008-12-30
landfill baby 修改于2018-04-16
使用flash来进行简单的复制操作似乎有些矫枉过正,很高兴有一个干净的JS方法来做这个。由于我们是在一个企业环境中。IE就可以了。谢谢Bandi!Eddie 2011-01-26
请解释一下execCommand(\\’copy\\’);的作用,如果不是复制到剪贴板的IE?@mrBornaRozzA 2012-04-24
不要使用if(!document.all),而要使用if(!r.execCommand),以免有其他人实现它!Document.all与此绝对不相关。m93a 2013-04-15
当人们使用Flash来改变剪贴板时,为什么十年来从未提出过这些隐私问题?如果我们只允许一种方式(即复制,而不是阅读其内容),这怎么会产生隐私问题?Muhammad bin Yusrat 2015-06-06
@MuhammadbinYusrat:虽然不是隐私问题,但它个用户体验问题。考虑到用户已经复制了一些东西,并认为他知道剪贴板上有什么,然后浏览你的网站,突然剪贴板上有一些他没有要求的东西,而且他已经失去了他首先复制的东西。awe 2015-10-02
#6楼
得票数 93

如果您想要一个真正简单的解决方案(只需不到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}

Brent Matzelle 提问于2010-10-17
Peter Mortensen 修改于2021-01-13
对于任何有兴趣的人来说,在GitHub上复制repo的URL时,可以查看Clippy被使用。Radek 2011-05-23
#7楼
得票数 82

我最近就这个问题写了一篇技术博文(我在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的方法,这是唯一跨浏览器的方法(据我所知)。

除此以外,还有一些以浏览器为单位的选项。

这在Internet Explorer中是最简单的,你可以随时从JavaScript中通过访问clipboardData对象:

window.clipboardData

(然而,当你试图在系统剪切、复制或粘贴事件之外这样做时,Internet Explorer会提示用户授予网络应用程序剪贴板的权限)。

在Chrome浏览器中,您可以创建一个Chrome扩展,该扩展将为您提供clipboard权限(这就是我们为Lucidchart做的事情)。然后对于安装了你的扩展的用户,你只需要自己触发系统事件:

document.execCommand('copy');

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

Richard Shurtz 提问于2014-12-03
Josh Correia 修改于2023-02-01
博文中没有提到(我希望能在不久的将来更新),就是使用execCommand触发剪切和复制的能力。这在IE10+、Chrome 43+和Opera29+中得到了支持。请在这里阅读有关信息。updates.html5rocks.com/2015/04/cut-and-copy-commandsRichard Shurtz 2015-05-20
这样做的一个问题是,它劫持了其他正常的复制事件。Brock Adams 2017-02-04
#8楼
得票数 73

我喜欢这个人:

<input onclick="this.select();" type='text' value='copy me' />

如果一个用户不知道如何在他们的操作系统中复制文本,那么很可能他们也不知道如何粘贴。因此,只要让它自动选择,其余的就留给用户。

Matthew Scragg 提问于2013-04-23
Josh Crozier 修改于2013-10-11
我也喜欢它,因为它很短。你也可以复制:<input onclick="this.select(); document.execCommand('copy');" type='text' value='copy me' />Roubi 2021-05-28
#9楼
得票数 59

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>

剪贴板.js也在GitHub上。

注意:现在这已经被废弃了。迁移到这里

a coder 提问于2015-08-11
tripulse 修改于2019-02-28
这个库被angular.io用于其英雄之旅,并在浏览器不支持execCommand的情况下以优雅模式回退,显示一个预选的文本,用户只需复制即可。John-Philip 2017-01-30
看起来要么是clipboard.js被替换了,要么是分叉了,但它似乎还活着,并在npmjs.com/package/clipboard上得到了积极的维护。Joao 2019-06-18
#10楼
得票数 46

在2018年,这里是你可以去做的事情:

async copySomething(text?) {
  try {
    const toCopy = text || location.href;
    await navigator.clipboard.writeText(toCopy);
    console.log('Text or Page URL copied');
  }
  catch (err) {
    console.error('Failed to copy: ', err);
  }
}

在我的Angular 6+代码中,它是这样使用的:

<button mat-menu-item (click)="copySomething()">
    <span>Copy link</span>
</button>

如果我传入一个字符串,它就复制它。如果没有,它就复制页面的URL。

也可以对剪贴板进行更多操作。在此处查看更多信息:

解除对剪贴板访问的阻挠

KhoPhi 提问于2018-08-06
Peter Mortensen 修改于2019-10-27
你已经链接到了localhostJoe Warner 2018-08-06
请注意,这在Safari浏览器(11.1.2版)中不起作用。arjunattam 2018-08-20
@arjun27 好吧,希望有一天苹果会赶上。虽然这个caniuse.com/#feat=clipboard显示你提到的上述版本被部分支持。KhoPhi 2018-08-20
根据所提供的链接,"navigator.clipboard只支持通过HTTPS提供的页面";TimH - Codidact 2018-12-20
#11楼
得票数 46

我非常成功地使用了这个方法(没有jQuery或任何其他框架)。

function copyToClp(txt){
    var m = document;
    txt = m.createTextNode(txt);
    var w = window;
    var b = m.body;
    b.appendChild(txt);
    if (b.createTextRange) {
        var d = b.createTextRange();
        d.moveToElementText(txt);
        d.select();
        m.execCommand('copy');
    } 
    else {
        var d = m.createRange();
        var g = w.getSelection;
        d.selectNodeContents(txt);
        g().removeAllRanges();
        g().addRange(d);
        m.execCommand('copy');
        g().removeAllRanges();
    }
    txt.remove();
}

警告:在此情况下,请勿使用 "不正当手段"。

选项卡被转换为空格(至少在Chrome中是这样)。

Grim 提问于2018-07-01
Grim 修改于2021-05-30
在火狐浏览器上不工作,我得到了一个错误,说是缺乏用户的激活。Luke_ 2021-10-08
@Luke_火狐是对的吗?你在没有用户直接点击的情况下调用它吗?Grim 2021-10-08
在FF 111.0.1(64位)中没有问题Josem 2023-03-24
#12楼
得票数 37

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

Justin 提问于2013-11-21
Peter Mortensen 修改于2021-01-13
在iOS和安卓4.4系统中无法使用Flash的跨浏览器功能Raptor 2014-01-27
查看更新的答案。这允许 flash 用户减少步骤,并为其他人提供后备。Justin 2014-01-27
它有10亿行代码。这绝对是荒谬的。与其在一个项目中包括这样一个怪物,还不如不做。vsync 2014-10-27
有一个简单的版本gist.github.com/JamesMGreene/8698897,是20K,没有74K版本的所有功能。这两个版本都不是非常大。我的猜测是,大多数用户都能接受74k或20k的文件被下载所需的额外毫秒,因此复制/粘贴只需点击一次而不是两次。Justin 2014-10-27
@Justin 我就是不能让它在本地工作,即使我复制&粘贴例子(我做了最小的改动,例如脚本标签中src的值)。我觉得他们的文档很漂亮,但效率很低。Gui Imamura 2015-07-23
#13楼
得票数 31

由于Chrome 42+和Firefox 41+现在支持document.execCommand('copy')命令,我使用Tim Down的旧答案Google Developer的答案的组合,为跨浏览器复制到剪贴板的能力创建了几个函数:

function selectElementContents(el) {
    // Copy textarea, pre, div, etc.
    if (document.body.createTextRange) {
        // Internet Explorer
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.select();
        textRange.execCommand("Copy");
    }
    else if (window.getSelection && document.createRange) {
        // Non-Internet Explorer
        var range = document.createRange();
        range.selectNodeContents(el);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
        try {
            var successful = document.execCommand('copy');
            var msg = successful ? 'successful' : 'unsuccessful';
            console.log('Copy command was ' + msg);
        }
        catch (err) {
            console.log('Oops, unable to copy');
        }
    }
} // end function selectElementContents(el)

function make_copy_button(el) {
    var copy_btn = document.createElement('input');
    copy_btn.type = "button";
    el.parentNode.insertBefore(copy_btn, el.nextSibling);
    copy_btn.onclick = function() {
        selectElementContents(el);
    };

    if (document.queryCommandSupported("copy") || parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 42) {
        // Copy works with Internet Explorer 4+, Chrome 42+, Firefox 41+, Opera 29+
        copy_btn.value = "Copy to Clipboard";
    }
    else {
        // Select only for Safari and older Chrome, Firefox and Opera
        copy_btn.value = "Select All (then press Ctrl + C to Copy)";
    }
}
/* Note: document.queryCommandSupported("copy") should return "true" on browsers that support copy,
    but there was a bug in Chrome versions 42 to 47 that makes it return "false".  So in those
    versions of Chrome feature detection does not work!
    See https://code.google.com/p/chromium/issues/detail?id=476508
*/

make_copy_button(document.getElementById("markup"));
<pre id="markup">
  Text that can be copied or selected with cross browser support.
</pre>

Jeff Baker 提问于2015-11-05
Peter Mortensen 修改于2021-01-13
#14楼
得票数 31

在JavaScript/TypeScript中,最好的和简单的方法是使用这个命令

navigator.clipboard.writeText(textExample);

只需在textExample中传递你想复制到剪贴板的值即可。

Tauseef Arshad 提问于2022-01-29
navigator.clipboard可以被限制。你应该抓住这个异常...Daniel 2022-02-03
不能在IOS系统中使用Lowis 2022-04-21
根据MDN剪贴板文档(developer.mozilla.org/en-US/docs/Web/API/Clipboard),该功能仅在安全情况下(HTTPS),在某些或所有支持的浏览器中才可用。vesmihaylov 2022-10-28
能看到一个行之有效的解决方案总是很好。选定的答案是可以的,但有时在试图使一些东西发挥作用时,长的答案会让人觉得太累。carloswm85 2023-03-23
#15楼
得票数 26

我已经把我认为最好的一个放在一起了。

  • 使用cssText来避免在Internet Explorer中出现异常,而不是直接使用样式。
  • 如果有选择,则恢复选择。
  • 设置为只读,这样在移动设备上就不会出现键盘了
  • 有一个针对iOS的解决方法,这样它就能真正发挥作用,因为它通常会阻止execCommand的运行。

在这里,它是:

const copyToClipboard = (function initClipboardText() {
  const textarea = document.createElement('textarea');

  // Move it off-screen.
  textarea.style.cssText = 'position: absolute; left: -99999em';

  // Set to readonly to prevent mobile devices opening a keyboard when
  // text is .select()'ed.
  textarea.setAttribute('readonly', true);

  document.body.appendChild(textarea);

  return function setClipboardText(text) {
    textarea.value = text;

    // Check if there is any content selected previously.
    const selected = document.getSelection().rangeCount > 0 ?
      document.getSelection().getRangeAt(0) : false;

    // iOS Safari blocks programmatic execCommand copying normally, without this hack.
    // https://stackoverflow.com/questions/34045777/copy-to-clipboard-using-javascript-in-ios
    if (navigator.userAgent.match(/ipad|ipod|iphone/i)) {
      const editable = textarea.contentEditable;
      textarea.contentEditable = true;
      const range = document.createRange();
      range.selectNodeContents(textarea);
      const sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(range);
      textarea.setSelectionRange(0, 999999);
      textarea.contentEditable = editable;
    }
    else {
      textarea.select();
    }

    try {
      const result = document.execCommand('copy');

      // Restore previous selection.
      if (selected) {
        document.getSelection().removeAllRanges();
        document.getSelection().addRange(selected);
      }

      return result;
    }
    catch (err) {
      console.error(err);
      return false;
    }
  };
})();

使用方法:copyToClipboard('some text')

Dominic 提问于2017-07-25
Andhi Irawan 修改于2020-10-22
在Opera等系统中不工作。Khom Nazid 2022-04-13
#16楼
得票数 26

其他方法将复制纯文本到剪贴板。要复制HTML(即你可以将结果粘贴到所见即所得的编辑器中),你可以在Internet Explorer only中进行如下操作。这与其他方法有根本的不同,因为浏览器实际上是明显地选择内容。

// Create an editable DIV and append the HTML content you want copied
var editableDiv = document.createElement("div");
with (editableDiv) {
    contentEditable = true;
}
editableDiv.appendChild(someContentElement);

// Select the editable content and copy it to the clipboard
var r = document.body.createTextRange();
r.moveToElementText(editableDiv);
r.select();
r.execCommand("Copy");

// Deselect, so the browser doesn't leave the element visibly selected
r.moveToElementText(someHiddenDiv);
r.select();
Chase Seibert 提问于2008-12-30
Peter Mortensen 修改于2021-01-13
在这里可以看到更完整的HTML解决方案 stackoverflow.com/questions/34191780/…kofifus 2015-12-17
#17楼
得票数 26

我找到了以下的解决方案:

按键式处理程序创建了一个"pre"标签。我们设置要复制的内容到这个标签,然后在这个标签上进行选择并在处理程序中返回true。这就调用了Chrome的标准处理程序,并复制了选定的文本。

如果你需要,你可以为恢复前一个选择的函数设置超时。我在MooTools上的实现:

function EnybyClipboard() {
    this.saveSelection = false;
    this.callback = false;
    this.pastedText = false;

    this.restoreSelection = function() {
        if (this.saveSelection) {
            window.getSelection().removeAllRanges();
            for (var i = 0; i < this.saveSelection.length; i++) {
                window.getSelection().addRange(this.saveSelection[i]);
            }
            this.saveSelection = false;
        }
    };

    this.copyText = function(text) {
        var div = $('special_copy');
        if (!div) {
            div = new Element('pre', {
                'id': 'special_copy',
                'style': 'opacity: 0;position: absolute;top: -10000px;right: 0;'
            });
            div.injectInside(document.body);
        }
        div.set('text', text);
        if (document.createRange) {
            var rng = document.createRange();
            rng.selectNodeContents(div);
            this.saveSelection = [];
            var selection = window.getSelection();
            for (var i = 0; i < selection.rangeCount; i++) {
                this.saveSelection[i] = selection.getRangeAt(i);
            }
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(rng);
            setTimeout(this.restoreSelection.bind(this), 100);
        } else return alert('Copy did not work. :(');
    };

    this.getPastedText = function() {
        if (!this.pastedText) alert('Nothing to paste. :(');
        return this.pastedText;
    };

    this.pasteText = function(callback) {
        var div = $('special_paste');
        if (!div) {
            div = new Element('textarea', {
                'id': 'special_paste',
                'style': 'opacity: 0;position: absolute;top: -10000px;right: 0;'
            });
            div.injectInside(document.body);
            div.addEvent('keyup', function() {
                if (this.callback) {
                    this.pastedText = $('special_paste').get('value');
                    this.callback.call(null, this.pastedText);
                    this.callback = false;
                    this.pastedText = false;
                    setTimeout(this.restoreSelection.bind(this), 100);
                }
            }.bind(this));
        }
        div.set('value', '');
        if (document.createRange) {
            var rng = document.createRange();
            rng.selectNodeContents(div);
            this.saveSelection = [];
            var selection = window.getSelection();
            for (var i = 0; i < selection.rangeCount; i++) {
                this.saveSelection[i] = selection.getRangeAt(i);
            }
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(rng);
            div.focus();
            this.callback = callback;
        } else return alert('Failed to paste. :(');
    };
}

使用方法:

enyby_clip = new EnybyClipboard(); // Init

enyby_clip.copyText('some_text'); // Place this in the Ctrl+C handler and return true;

enyby_clip.pasteText(function callback(pasted_text) {
    alert(pasted_text);
}); // Place this in Ctrl+V handler and return true;

在粘贴时,它创建了一个文本区域,并以同样的方式工作。

PS:也许这个方案可以用来创建一个没有Flash的完整的跨浏览器解决方案。它可以在Firefox和Chrome中使用。

Enyby 提问于2012-07-05
Enyby 修改于2021-01-13
有人试过吗?听起来是个不错的东西,万一它真的能在一系列的浏览器上工作呢!Michael 2013-02-15
jsfiddle.net/H2FHC演示:fiddle.jshell.net/H2FHC/show请打开它并按Ctrl+V或Ctrl+C。在FF 19.0中分叉完美。在Chrome 25.0.1364.97米也是。Opera 12.14 - OK。 Safari 5.1.7 for Windows - OK。 IE - FAIL。Enyby 2013-02-28
对于IE需要在页面内的元素上运行焦点。参见 fiddle.jshell.net/H2FHC/3/showfiddle.jshell.net/H2FHC/3 在IE 9/10中工作。IE 6/7需要以其他方式创建选择,因为不支持document.createRange。Enyby 2013-02-28
#18楼
得票数 18

此代码在2021年5月测试过。在Chrome , IE , Edge上工作。下面的'message'参数是你要复制的字符串值。

<script type="text/javascript">
    function copyToClipboard(message) {
        var textArea = document.createElement("textarea");
        textArea.value = message;
        textArea.style.opacity = "0"; 
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();


        try {
            var successful = document.execCommand('copy');
            var msg = successful ? 'successful' : 'unsuccessful';
            alert('Copying text command was ' + msg);
        } catch (err) {
            alert('Unable to copy value , error : ' + err.message);
        }

        document.body.removeChild(textArea);
    }

</script>
HO LI Pin 提问于2021-05-20
HO LI Pin 修改于2021-05-20
#19楼
得票数 17

这可以直接工作,使用最新的Clipboard API,以及一个用户互动:

copy.addEventListener("pointerdown", () => navigator.clipboard.writeText("Hello World!"))
<button id="copy">Copy Hello World!</button>

NVRM 提问于2022-04-10
它并不奏效。user31782 2022-10-04
如果你在.writeText()中加入.then(),它就会起作用,因为它是一个Promise。Andi Aleksandrov 2023-02-01
#20楼
得票数 13

将HTML输入的文本复制到剪贴板上:

 function myFunction() {
   /* Get the text field */
   var copyText = document.getElementById("myInput");

   /* Select the text field */
   copyText.select();

   /* Copy the text inside the text field */
   document.execCommand("Copy");

   /* Alert the copied text */
   alert("Copied the text: " + copyText.value);
 }
 <!-- The text field -->
 <input type="text" value="Hello Friend" id="myInput">

 <!-- The button used to copy the text -->
<button onclick="myFunction()">Copy text</button>

注意: Internet Explorer 9和更早的版本不支持document.execCommand()方法

来源W3Schools - 将文本复制到剪贴板

Alexandru Sirbu 提问于2018-01-25
Peter Mortensen 修改于2019-10-27
#21楼
得票数 12

最好的方法是复制文本字段内的文本。 使用navigator.clipboard.writeText

<input type="text" value="Hello World" id="myId">
<button onclick="myFunction()" >Copy text</button>

<script>
function myFunction() {
  var copyText = document.getElementById("myId");
  copyText.select();
  copyText.setSelectionRange(0, 99999);
  navigator.clipboard.writeText(copyText.value);
}

</script>
Tauseef Arshad 提问于2021-12-19
document.execCommand('复制');命令总是不起作用,上面的方法解决了它PrashSE 2021-12-23
document.execCommand('Copy'); 命令可以使用,但'(commandId: string, showUI?: boolean | undefined, value?: string | undefined): boolean'的签名已经被废弃。Tauseef Arshad 2021-12-24
#22楼
得票数 11

我不愿意在这个问题上增加另一个答案,但为了帮助像我这样的菜鸟,而且因为这是谷歌的顶级结果,我将会这样做。

在2022年,要将文本复制到剪贴板,你要使用一行

navigator.clipboard.writeText(textToCopy);

这将返回一个Promise,如果它复制了,就会被解决,如果它失败了,就会被拒绝。

一个完整的工作功能是这样的:

async function copyTextToClipboard(textToCopy) {
    try {
        await navigator.clipboard.writeText(textToCopy);
        console.log('copied to clipboard')
    } catch (error) {
        console.log('failed to copy to clipboard. error=' + error);
    }
}

警告!如果你在测试时打开Chrome开发工具,将会失败因为浏览器要启用剪贴板,需要你有窗口的焦点。这是为了防止随机网站在你不希望的情况下改变你的剪贴板。Dev Tools会窃取这个焦点,所以关闭Dev Tools,你的测试就会成功。

如果你想复制其他东西(图片等)到剪贴板上,请看这些文件。

https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API

这在浏览器中得到了足够的支持,你可以使用它。如果你担心Firefox,可以使用权限查询来显示或隐藏该按钮,如果浏览器支持的话。https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query

Joshua Dance 提问于2022-10-10
async copyToClipboard(){ let text = "text on clipboard"; await navigator.clipboard.writeText(text); }调用这个函数后,你会知道变量text的期望值,你可以从剪贴板的任何地方粘贴。Kartik Chandra 2023-04-10
#23楼
得票数 10

我也有同样的问题,从(类似Excel的东西)建立一个自定义的网格编辑,并与Excel兼容。我不得不支持选择多个单元格,复制和粘贴。

解决方案:创建一个文本区域,在那里你将插入数据供用户复制(对于我来说,当用户选择单元格时),将焦点设置在它上面(例如,当用户按Ctrl时),并选择整个文本。

所以,当用户点击Ctrl+C时,他/她会得到复制的单元格,他/她选择。经过测试,只是将文本区域的大小调整到一个像素(我没有测试它是否会在 display:none 的情况下工作)。它在所有的浏览器上都能很好地工作,而且对用户是透明的。

粘贴--你可以这样做(取决于你的目标)--保持对文本区域的关注,并使用onpaste捕捉粘贴事件(在我的项目中,我在单元格中使用文本区域来编辑)。

我不能粘贴一个例子(商业项目),但你会明白这个道理。

xiniu 提问于2011-01-17
Josh Correia 修改于2023-02-01
#24楼
得票数 9

这是Chase Seibert的答案的扩展,其优点是它将适用于IMAGE和TABLE元素,而不仅仅是Internet Explorer 9上的DIV。

if (document.createRange) {
    // Internet Explorer 9 and modern browsers
    var r = document.createRange();
    r.setStartBefore(to_copy);
    r.setEndAfter(to_copy);
    r.selectNode(to_copy);
    var sel = window.getSelection();
    sel.addRange(r);
    document.execCommand('Copy');  // Does nothing on Firefox
} else {
    // Internet Explorer 8 and earlier. This stuff won't work
    // on Internet Explorer 9.
    // (unless forced into a backward compatibility mode,
    // or selecting plain divs, not img or table).
    var r = document.body.createTextRange();
    r.moveToElementText(to_copy);
    r.select()
    r.execCommand('Copy');
}
Oliver Bock 提问于2011-08-12
Peter Mortensen 修改于2021-01-13
#25楼
得票数 9

我已经使用了clipboard.js。

我们可以在npm上得到它:

npm install clipboard --save

还有就是在Bower上。

bower install clipboard --save

new ClipboardJS("#btn1");

document.querySelector("#btn2").addEventListener("click", () => document.querySelector("#btn1").dataset.clipboardText = Math.random());
<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>

<button id="btn1" data-clipboard-text="Text to copy goes here">
    Copy to clipboard
</button>
<button id="btn2">Click here to change data-clipboard-text</button>

<br /><br />

<input type="text" placeholder="Paste here to see clipboard" />

更多的用法& 例子在https://zenorocha.github.io/clipboard.js/

CodecPM 提问于2015-10-28
Samathingamajig 修改于2022-01-26
我担心它与动态内容不兼容,但它是;-)我认为这是一个更好的解决方案,现在,比2008年的旧方案更好。BENARD Patrick 2016-01-05
#26楼
得票数 6

我的错。这只在Internet Explorer中有效。

这里有另一种复制文本的方法:

<p>
    <a onclick="window.clipboardData.setData('text', document.getElementById('Test').innerText);">Copy</a>
</p>
dvallejo 提问于2013-09-13
Peter Mortensen 修改于2021-01-13
这在目前的Chrome(V31)或FireFox(V25)中不起作用。错误在于window.clipboardData是未定义的。从好的方面看,它在IE9中是有效的。所以,只要你不关心好的浏览器,想把你的网站锁定在坏的浏览器上,这就是你要做的事情Anthony 2013-11-14
我不明白为什么这么多愚蠢的答案。w3schools.com/howto/tryit.asp?filename=tryhow_js_copy_clipboardMartianMartian 2018-02-08
#27楼
得票数 4

这里是同一网站的simpleAjax/session based clipboard。

注意,会话必须启用&有效,这个方案对同一个网站也有效。我在CodeIgniter上测试了它,但我遇到了会话/Ajax问题,但this也解决了这个问题。如果你不想玩会话,可以使用数据库表。

JavaScript/jQuery

<script type="text/javascript">
    $(document).ready(function() {

        $("#copy_btn_id").click(function(){

            $.post("<?php echo base_url();?>ajax/foo_copy/"+$(this).val(), null,
                function(data){
                    // Copied successfully
                }, "html"
            );
        });

        $("#paste_btn_id").click(function() {

           $.post("<?php echo base_url();?>ajax/foo_paste/", null,
               function(data) {
                   $('#paste_btn_id').val(data);
               }, "html"
           );
        });
    });
</script>

HTML的内容

<input type='text' id='copy_btn_id' onclick='this.select();'  value='myvalue' />
<input type='text' id='paste_btn_id' value='' />

PHP代码

<?php
    class Ajax extends CI_Controller {

        public function foo_copy($val){
            $this->session->set_userdata(array('clipboard_val' => $val));
        }

        public function foo_paste(){
            echo $this->session->userdata('clipboard_val');
            exit();
        }
    }
?>
UserBSS1 提问于2013-08-06
UserBSS1 修改于2021-01-14