Chrome扩展中的复制到剪贴板

62

我正在为Google Chrome开发扩展程序,但遇到了一个难题。

我需要在单击弹出窗口中的readonly textarea时将其内容复制到剪贴板中。有没有人知道使用纯JavaScript且不使用Flash的最佳方法?如果可以的话,我也加载了jQuery库。我的当前(不起作用的)代码是...

function copyHTMLCB() {
$('#lb_html').select();
$('#lb_html').focus();
textRange = document.lb_html_frm.lb_html.createTextRange();
textRange.execCommand("RemoveFormat");
textRange.execCommand("Copy");
alert("HTML has been copied to your clipboard."); }
12个回答

68

所有功劳归于joelpt,但以防其他人需要在纯JavaScript中工作而没有jQuery(就像我一样),这是他解决方案的一个适应:

function copyTextToClipboard(text) {
  //Create a textbox field where we can insert text to. 
  var copyFrom = document.createElement("textarea");

  //Set the text content to be the text you wished to copy.
  copyFrom.textContent = text;

  //Append the textbox field into the body as a child. 
  //"execCommand()" only works when there exists selected text, and the text is inside 
  //document.body (meaning the text is part of a valid rendered HTML element).
  document.body.appendChild(copyFrom);

  //Select all the text!
  copyFrom.select();

  //Execute command
  document.execCommand('copy');

  //(Optional) De-select the text using blur(). 
  copyFrom.blur();

  //Remove the textbox field from the document.body, so no other JavaScript nor 
  //other elements can get access to this.
  document.body.removeChild(copyFrom);
}

它对我帮助很大!非常感谢您抽出时间再次用纯JS制作。 - LogoS
2
为什么不直接使用document.body而是要用var body = document.getElementsByTagName('body')[0];呢? - jscripter
@tom_mai78101 为什么要使用 document.body.removeChild(copyFrom)?而不是用copyFrom.remove()呢?这样做不更容易吗? - Shayan
1
@Shayan 我一直在保留原作者的代码,并没有真正考虑改进代码。这段代码最初是在2013年编写的。 - tom_mai78101
1
对于正在迁移到浏览器扩展程序的Manifest v3的人们...这些答案都不起作用,甚至包括剪贴板API,在服务工作者JavaScript中(通常在Manifest v2中称为后台脚本)参见此处。但是,当从用户的活动选项卡通过注入的脚本、您的扩展程序弹出式脚本或扩展程序选项页面脚本调用时,您仍然可以使用大多数这些选项来写入剪贴板,因为在这些情况下,您正在操作一个活动HTML文档的上下文。 - patridge
显示剩余5条评论

44

我发现以下方法最好,因为它允许您指定复制数据的MIME类型:

copy: function(str, mimeType) {
  document.oncopy = function(event) {
    event.clipboardData.setData(mimeType, str);
    event.preventDefault();
  };
  document.execCommand("copy", false, null);
}

实际上,当你使用这个功能后,你就无法从页面上复制其他任何内容了。我相信这是因为preventDefault()的原因。 - g.a

22

我正在使用这个简单的函数把任何给定的纯文本复制到剪贴板(仅在Chrome浏览器中使用,需要jQuery):

// Copy provided text to the clipboard.
function copyTextToClipboard(text) {
    var copyFrom = $('<textarea/>');
    copyFrom.text(text);
    $('body').append(copyFrom);
    copyFrom.select();
    document.execCommand('copy');
    copyFrom.remove();
}

// Usage example
copyTextToClipboard('This text will be copied to the clipboard.');

由于快速的附加-选择-复制-删除序列,似乎没有必要隐藏文本区域或给它任何特定的CSS/属性。至少在我的电脑上,在非常大的文本块被移除之前,Chrome甚至不会将其呈现到屏幕上。

请注意,这仅适用于Chrome扩展/应用程序。如果您使用的是v2 manifest.json,则应在其中声明“clipboardWrite”权限;这对于应用程序是强制性的,并建议为扩展使用。


获取 '$' 未定义。 - Mohammed Julfikar Ali Mahbub

19

剪贴板 API现在已经被 Chrome 支持,并且旨在替代 document.execCommand

来自 MDN:

navigator.clipboard.writeText(text).then(() => {
    //clipboard successfully set
}, () => {
    //clipboard write failed, use fallback
});

5
我尝试过这个,但它对我来说失败了。我是从一个后台脚本尝试的,这只能在内容脚本中工作吗?我还在清单文件中设置了clipboardWrite权限。 - trker
从内容脚本中对我有用 - Boris Yakubchik

6

7
链接失效了,有新的资源吗? - Victor S
5
这已不再是事实 - 它只需要拓展剪贴板读写权限。目前(jQuery)最佳解决方案似乎在这里https://dev59.com/mWw05IYBdhLWcg3wmC6_#7147192。 - iono
3
文档链接已失效。 - user404021
@DimaFomin 这是针对Chrome Web应用程序复制/粘贴图像数据的,而您需要使用developer.chrome.com/extensions/declare_permissions来处理Chrome扩展程序。看起来这个链接是唯一提到clipboardReadclipboardWrite的地方。 - tom_mai78101
剪贴板 API 不再是实验性的,请参见我的答案了解详情。 - Kartik Soneji
1
过时的答案,现在已经有更好的解决方案在该帖子中可用。楼主应考虑取消将其标记为已接受的答案。 - DeZeA

3
您不能使用execCommand("Copy")复制只读文本,它必须是可编辑的文本区域。解决方案是创建一个文本输入元素,并从那里复制文本。不幸的是,您不能使用display: nonevisibility: hidden隐藏该元素,因为这也会阻止选择/复制命令的工作。但是,您可以使用负边距“隐藏”它。这是我在Chrome扩展程序弹出窗口中获取短网址时所做的事情。这是重写带有shorturl的弹出窗口的代码部分(快速且脏的方法;-)):
document.body.innerHTML = '<p><a href="'+shortlink+'" target="_blank" >'+shortlink+'</a><form style="margin-top: -35px; margin-left: -500px;"><input type="text" id="shortlink" value="'+shortlink+'"></form></p>'
document.getElementById("shortlink").select()
document.execCommand("Copy") 

2

只有这个对我起作用。

我认为 document.execCommand 在 Chrome 中根本不起作用。

我在代码中保留了 execCommand,但可能只是因为一个简单的原因:让这个东西存在 :)

我浪费了很多时间在上面,而没有查看我的旧笔记。

    function copy(str, mimeType) {
        document.oncopy = function(event) {
            event.clipboardData.setData(mimeType, str);
            event.preventDefault();
        };
        try{            
            var successful = document.execCommand('copy', false, null);
            var msg = successful ? 'successful' : 'unsuccessful';
            console.log('Copying text command was ' + msg);
            if (!successful){
                navigator.clipboard.writeText(str).then(
                    function() {
                        console.log('successful')
                    }, 
                    function() {
                        console.log('unsuccessful')
                    }
                );
            }
        }catch(ex){console.log('Wow! Clipboard Exeption.\n'+ex)}
    }

1

我在某处读到,Javascript存在安全限制,阻止你与操作系统进行交互。我以前使用过ZeroClipboard(http://code.google.com/p/zeroclipboard/),效果很好,但它确实使用了Flash。Bitly网站非常有效地使用了它:http://bit.ly/


1
let content = document.getElementById("con");
content.select();
document.execCommand("copy");

上述代码在任何情况下都可以完美运行。只需确保从中提取内容的字段应为可编辑字段,例如输入字段。

0
我曾经遇到过一个类似的问题,需要使用JavaScript从元素中复制文本。我将在此为有兴趣的人添加解决方案。这个解决方案适用于许多HTML元素,包括textarea。
HTML:
    <textarea id="text-to-copy">This is the text I want to copy</textarea>
    <span id="span-text-to-copy">This is the text I want to copy</span>

JavaScript:

let textElement = document.getElementById("text-to-copy");

//remove selection of text before copying. We can also call this after copying
window.getSelection().removeAllRanges();

//create a Range object
let range = document.createRange();

//set the Range to contain a text node.
range.selectNode(textElement);

//Select the text node
window.getSelection().addRange(range);

try {
    //copy text
    document.execCommand('copy');
} catch(err) {
    console.log("Not able to copy ");
}

请注意,如果您想复制一个 span 元素,那么您可以获取它的文本节点,并将其用作 range.selectNode() 的参数来选择该文本:
let elementSpan = document.getElementById("span-text-to-copy");
let textNode = elementSpan.childNodes[0];

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