点击按钮复制到剪贴板。

565

我该如何将一个div中的文本复制到剪贴板?我有一个div,需要添加一个链接,以将文本添加到剪贴板。这个问题有解决方案吗?

<p class="content">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>

<a class="copy-text">copy Text</a>

我点击复制文本后,再按Ctrl + V,就可以粘贴。


请参考以下链接:https://dev59.com/fHRC5IYBdhLWcg3wJNcN - SquareCat
Trello有一种巧妙的方式可以在没有Flash的情况下实现这一点: https://dev59.com/hmMm5IYBdhLWcg3wi_i0 - Paul Schreiber
1
@MichaelScheper - 一些用户甚至聪明到注意到我的评论以及这里的大多数答案是四年前发表的,当时基于一个小型 Flash 应用的 zeroclipboard 是使用剪贴板的唯一跨浏览器可行选项和解决方案。现在,所有现代浏览器都本地支持它,所以这不再是问题,但在2014年那时情况并非如此。 - adeneo
@adeneo:很高兴听到第一部分,它解决了我的担忧。很抱歉我的评论显得过于批评,但这并不意味着你的总是错的...我有点惊讶你的反应如此敌对,老实说。尽管如此,我承认我从来不是Flash的粉丝,而且认为它是一个能够在任何地方快速修复的态度是一个令人讨厌的问题,特别是对于移动浏览器!而且我非常清楚网络已经发生了变化——我已经从事网站开发超过20年了。所以我希望你也会在StackOverflow评论过时时提到它。 - Michael Scheper
1
@MichaelScheper - 你的评论并没有显得过于批评,而是完全不合时宜和傲慢自大。四年后发表“严肃地说,没有……flash是邪恶的,用户知道更好……”这样的评论似乎完全多余了,我们都知道现在已经没有人再使用flash了,它在所有平台上都不受支持等等,下面的答案也已经更新以反映这一点。然而,在那些答案和我的评论首次发布时,flash是唯一可行的答案,因此我的评论仍然存在,即使只是出于历史目的。绝对没有必要将其删除。 - adeneo
显示剩余5条评论
33个回答

852

2020年更新:此解决方案使用execCommand。虽然在撰写本答案时该功能很好,但现在已被视为过时。它仍将在许多浏览器上工作,但不建议使用,因为支持可能会被放弃。

除了Clipboard API(在jfriend00的回答中提到)之外,还有另一种非Flash方式。您需要选择文本,然后执行命令copy,以将当前在页面上选定的任何文本复制到剪贴板上。

例如,此函数将把传递元素的内容复制到剪贴板中(根据PointZeroTwo在评论中的建议进行更新):

function copyToClipboard(element) {
    var $temp = $("<input>");
    $("body").append($temp);
    $temp.val($(element).text()).select();
    document.execCommand("copy");
    $temp.remove();
}

这是它的工作原理:
  1. 创建一个临时隐藏的文本字段。
  2. 将元素的内容复制到该文本字段中。
  3. 选择文本字段的内容。
  4. 执行命令复制,如:document.execCommand("copy")
  5. 删除临时文本字段。
注意,元素的内部文本可能包含空格。因此,如果您想将其用于密码等用途,则可以使用上面代码中的$(element).text().trim()修剪文本。
您可以在此处查看快速演示:

function copyToClipboard(element) {
  var $temp = $("<input>");
  $("body").append($temp);
  $temp.val($(element).text()).select();
  document.execCommand("copy");
  $temp.remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p id="p1">P1: I am paragraph 1</p>
<p id="p2">P2: I am a second paragraph</p>
<button onclick="copyToClipboard('#p1')">Copy P1</button>
<button onclick="copyToClipboard('#p2')">Copy P2</button>
<br/><br/><input type="text" placeholder="Paste here for test" />

主要问题在于目前并非所有的浏览器都支持这个功能,但您可以在以下主要浏览器上使用:

  • Chrome 43
  • Internet Explorer 10
  • Firefox 41
  • Safari 10

更新1:这也可以通过纯JavaScript解决方案实现(无需jQuery):

function copyToClipboard(elementId) {

  // Create a "hidden" input
  var aux = document.createElement("input");

  // Assign it the value of the specified element
  aux.setAttribute("value", document.getElementById(elementId).innerHTML);

  // Append it to the body
  document.body.appendChild(aux);

  // Highlight its content
  aux.select();

  // Copy the highlighted text
  document.execCommand("copy");

  // Remove it from the body
  document.body.removeChild(aux);

}
<p id="p1">P1: I am paragraph 1</p>
<p id="p2">P2: I am a second paragraph</p>
<button onclick="copyToClipboard('p1')">Copy P1</button>
<button onclick="copyToClipboard('p2')">Copy P2</button>
<br/><br/><input type="text" placeholder="Paste here for test" />

注意,现在我们传递id时不需要使用#符号。
如下评论区madzohan所述,在某些情况下(本地运行文件时),64位版本的Google Chrome存在一些奇怪的问题。使用上述非jQuery解决方案可以解决此问题。
Madzohan尝试在Safari中使用document.execCommand('SelectAll')而不是使用.select()(如聊天和下面的评论所指定)来解决该问题,而该解决方案也奏效了。
正如PointZeroTwo在评论中所指出,可以改进代码以返回成功/失败结果。您可以在this jsFiddle上查看演示。

更新:复制保留文本格式

正如用户在西班牙版StackOverflow上指出的那样,如果您想要逐字复制元素的内容,则上面列出的解决方案完美地工作,但如果您想要带格式粘贴已复制的文本(因为它被复制到了一个input type="text"中,所以格式会丢失),则效果不佳。

解决方案是将其复制到可编辑的div中,然后使用类似的方式使用execCommand进行复制。这里有一个示例-单击复制按钮,然后粘贴到下面的可编辑框中:

function copy(element_id){
  var aux = document.createElement("div");
  aux.setAttribute("contentEditable", true);
  aux.innerHTML = document.getElementById(element_id).innerHTML;
  aux.setAttribute("onfocus", "document.execCommand('selectAll',false,null)"); 
  document.body.appendChild(aux);
  aux.focus();
  document.execCommand("copy");
  document.body.removeChild(aux);
}
#target {
  width:400px;
  height:100px;
  border:1px solid #ccc;
}
<p id="demo"><b>Bold text</b> and <u>underlined text</u>.</p>
<button onclick="copy('demo')">Copy Keeping Format</button> 

<div id="target" contentEditable="true"></div>

而在jQuery中,它会像这样:

function copy(selector){
  var $temp = $("<div>");
  $("body").append($temp);
  $temp.attr("contenteditable", true)
       .html($(selector).html()).select()
       .on("focus", function() { document.execCommand('selectAll',false,null); })
       .focus();
  document.execCommand("copy");
  $temp.remove();
}
#target {
  width:400px;
  height:100px;
  border:1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<p id="demo"><b>Bold text</b> and <u>underlined text</u>.</p>
<button onclick="copy('#demo')">Copy Keeping Format</button> 

<div id="target" contentEditable="true"></div>


5
奇怪...在这里它可用,但是我无法在本地让它工作。使用jquery-1.11.3和Chrome 43.0.2357.130(64位)。 - madzohan
2
@madzohan 好的,我成功地重现了这个问题。很奇怪,因为我只在本地(file://)的64位Chrome上重现了它。我还找到了一个快速解决方案,适用于我:使用纯JavaScript而不是jQuery。我将更新答案并提供该代码。请检查它并告诉我是否有效。 - Alvaro Montoro
1
jQuery版本可以稍微改进一下,不使用“#temp”id,这可能会与页面上的其他内容发生冲突。首先使用以下代码创建临时输入对象:var $temp = $("<input />");,然后将$temp附加到页面上,并调用$temp.remove()来删除它。请参见https://jsfiddle.net/tvkrdjs8/1/(还包括一些关于execCommand的错误处理)。 - PointZeroTwo
3
直到我添加了以下行来确保页面上显示aux,这个方法才对我起作用: aux.style.position = "fixed"; aux.style.top = 0;appendChild调用之前加入这些行。 - ariscris
8
由于原始的jQuery实现使用了INPUT元素,因此无法保留换行符。改用TEXTAREA元素可以解决这个问题。 - thomasfuchs
显示剩余30条评论

515

2016年更新:

截至2016年,现在大多数浏览器都能够使用document.execCommand("copy")将文字复制到剪贴板,因为大多数浏览器有编程能力,可以根据选定内容编程地将文本复制到剪贴板。

与浏览器中的其他操作(如打开新窗口)一样,只能通过特定的用户操作(如鼠标单击)才能完成剪贴板复制。例如,不能通过计时器等方式来完成。

以下是一个代码示例:

document.getElementById("copyButton").addEventListener("click", function() {
    copyToClipboard(document.getElementById("copyTarget"));
});

function copyToClipboard(elem) {
   // create hidden text element, if it doesn't already exist
    var targetId = "_hiddenCopyText_";
    var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
    var origSelectionStart, origSelectionEnd;
    if (isInput) {
        // can just use the original source element for the selection and copy
        target = elem;
        origSelectionStart = elem.selectionStart;
        origSelectionEnd = elem.selectionEnd;
    } else {
        // must use a temporary form element for the selection and copy
        target = document.getElementById(targetId);
        if (!target) {
            var target = document.createElement("textarea");
            target.style.position = "absolute";
            target.style.left = "-9999px";
            target.style.top = "0";
            target.id = targetId;
            document.body.appendChild(target);
        }
        target.textContent = elem.textContent;
    }
    // select the content
    var currentFocus = document.activeElement;
    target.focus();
    target.setSelectionRange(0, target.value.length);
    
    // copy the selection
    var succeed;
    try {
       succeed = document.execCommand("copy");
    } catch(e) {
        succeed = false;
    }
    // restore original focus
    if (currentFocus && typeof currentFocus.focus === "function") {
        currentFocus.focus();
    }
    
    if (isInput) {
        // restore prior selection
        elem.setSelectionRange(origSelectionStart, origSelectionEnd);
    } else {
        // clear temporary content
        target.textContent = "";
    }
    return succeed;
}
input {
  width: 400px;
}
<input type="text" id="copyTarget" value="Text to Copy"> <button id="copyButton">Copy</button><br><br>
<input type="text" placeholder="Click here and press Ctrl-V to see clipboard contents">


这是一个稍微高级一些的演示:https://jsfiddle.net/jfriend00/v9g1x0o6/

而且,你也可以使用预先构建的库clipboard.js来为你完成此操作。


旧的、历史性的回答部分

由于安全原因,任何现代浏览器都不允许通过JavaScript直接复制到剪贴板。最常见的解决方法是使用Flash功能来复制到剪贴板,只有通过直接用户点击才能触发。

如前所述,ZeroClipboard是一个流行的代码集,用于管理Flash对象进行复制。我已经使用过它。如果在浏览设备上安装了Flash(这排除了移动设备或平板电脑),它可以正常工作。


下一个最常见的解决方法是将剪贴板绑定的文本放入输入字段中,将焦点移动到该字段并建议用户按Ctrl+C复制文本。
有关此问题和可能的解决方法的其他讨论可以在以下先前的Stack Overflow帖子中找到:

这些问题询问关于使用Flash的现代替代方案,已经得到了很多赞同,并且没有提供解决方案的答案(可能是因为不存在):


Internet Explorer和Firefox曾经拥有非标准的API用于访问剪贴板,但它们更现代化的版本已经弃用了这些方法(可能是出于安全原因)。


有一个初步的标准努力正在进行,试图找到一种“安全”的方式来解决最常见的剪贴板问题(可能需要像Flash解决方案那样的特定用户操作),看起来最新版本的Firefox和Chrome可能已经部分实现了这个努力,但我还没有确认。


1
clipboard.js 刚刚被添加到这篇编辑过的文章中。这是一个很好的实用工具,我在2015年8月将其作为回答此问题的一部分包含了进去。 - a coder
1
@acoder - 剪贴板支持一直在不断变化。例如,Firefox 直到最近(2015 年底)才在足够的情况下启用了 document.execCommand("copy"),可以依靠它来使用。因此,我正在努力保持我的答案最新(最初是在将近两年前编写的)。我们仍然没有可靠的 Safari 解决方案,除了预先选择文本并告诉用户手动按 Ctrl+C,但至少在其他地方正在取得进展。 - jfriend00
1
这里是剪贴板API支持的链接:http://caniuse.com/#feat=clipboard - L84
2
请注意,根据这个Safari版本说明,Safari 10现在支持document.execCommand("copy"),因此这段代码现在应该可以在Safari 10中正常工作。 - jfriend00
1
@sebastiangodelet - 公共领域。 - jfriend00
显示剩余13条评论

84

2023年1月

从2023年开始,您应该使用剪贴板API

navigator.clipboard.writeText('text here you want to copy').then(function () {
    alert('It worked! Do a CTRL - V to paste')
}, function () {
    alert('Failure to copy. Check permissions for clipboard')
});

这里有关于与剪贴板交互的更多信息。


5
使用jQuery,您可以将以下代码添加到任何HTML元素中:onclick="navigator.clipboard.writeText($(this).text());" - stomtech

63

2022年6月

更新:现在正确的方式是使用Clipboard API

例如:

// get the text from the DOM Element: 
const textToCopy = document.querySelector('.content').innerText

// when someone clicks on the <a class="copy-text"> element 
// (which should be a <button>), execute the copy command:
document.querySelector('.copy-text').addEventListener('click' , ()=> {
  navigator.clipboard.writeText(textToCopy).then(
    function() {
      /* clipboard successfully set */
      window.alert('Success! The text was copied to your clipboard') 
    }, 
    function() {
      /* clipboard write failed */
      window.alert('Opps! Your browser does not support the Clipboard API')
    }
  )
})

就这些。



如果您想在 Clipboard API 推出之前查看解决方案(现今不是一个好的实践方式):

$('button.copyButton').click(function(){
    $(this).siblings('input.linkToCopy').select();      
    document.execCommand("copy");
});
HTML:
<button class="copyButton">click here to copy</button>
<input class="linkToCopy" value="TEXT TO COPY"
style="position: absolute; z-index: -999; opacity: 0;" />

似乎在iPad上无法正常工作,尚未测试,但建议的解决方案在此处:https://dev59.com/ulsX5IYBdhLWcg3wRNjK#34046084 - user1063287
这对我有用,但如果要复制的文本包含回车符,则可以使用文本区域。 - Alex
如果剪贴板API不可用,例如在本地主机上,你的错误信息将无法访问。 - Chris Pink

37

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 上

2016年1月15日更新: 最佳答案 今天进行了编辑,以引用我在2015年8月发布的答案中相同的API。先前的文本指导用户使用 ZeroClipboard。只是想明确一下,我没有从 jfriend00 的答案中拿走这个,而是相反的情况。


clipboard-js 已经被弃用作者留言:请迁移到 https://github.com/lgarron/clipboard-polyfill - Yevgeniy Afanasyev

18

带有换行符(Alvaro Montoro回答的扩展部分)

var ClipboardHelper = {

    copyElement: function ($element)
    {
       this.copyText($element.text())
    },
    copyText:function(text) // Linebreaks with \n
    {
        var $tempInput =  $("<textarea>");
        $("body").append($tempInput);
        $tempInput.val(text).select();
        document.execCommand("copy");
        $tempInput.remove();
    }
};

ClipboardHelper.copyText('Hello\nWorld');
ClipboardHelper.copyElement($('body h1').first());

14

没有使用Flash或其他要求,更好的方法是clipboard.js。你只需要在任何按钮上添加data-clipboard-target="#toCopyElement",初始化new Clipboard('.btn');,它就会将具有id toCopyElement的DOM内容复制到剪贴板中。这是一个代码片段,通过链接复制提供的问题文本。

不过,它有一个限制,即它不能在Safari上使用,但它在所有其他浏览器(包括移动浏览器)上工作,因为它不使用Flash。

$(function(){
  new Clipboard('.copy-text');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/clipboard.js/1.5.12/clipboard.min.js"></script>

<p id="content">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>

<a class="copy-text" data-clipboard-target="#content" href="#">copy Text</a>


10
<div class="form-group">
    <label class="font-normal MyText">MyText to copy</label>&nbsp;
    <button type="button" class="btn btn-default btn-xs btnCopy" data="MyText">Copy</button>
</div>


$(".btnCopy").click(function () {
        var element = $(this).attr("data");
        copyToClipboard($('.' + element));
  });

function copyToClipboard(element) {
    var $temp = $("<input>");
    $("body").append($temp);
    $temp.val($(element).text()).select();
    document.execCommand("copy");
    $temp.remove();
}

不错的解决方法。也许可以在<input>标签中添加.addClass("hidden"),使其永远不会在浏览器中显示? - Roland

8

jQuery简单解决方案。

应该由用户的点击触发。

$("<textarea/>").appendTo("body").val(text).select().each(function () {
            document.execCommand('copy');
        }).remove();

6
你可以使用此代码,在单击按钮时将页面上输入的值复制到剪贴板中。
这是HTML。
<input type="text" value="xxx" id="link" class="span12" />
<button type="button" class="btn btn-info btn-sm" onclick="copyToClipboard('#link')">
    Copy Input Value
</button>

针对这个HTML代码,我们必须使用以下的JQuery代码:

function copyToClipboard(element) {
    $(element).select();
    document.execCommand("copy");
}

这是该问题的最简解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接