javascript剪切/复制/粘贴到剪贴板:谷歌是如何解决它的?

时间:2012-03-11 19:43:57

标签: javascript copy clipboard paste

是的,这个问题一再被问到:如何使用javascript从系统剪贴板复制粘贴到系统剪贴板?到目前为止,我发现只有部分解决方案和黑客攻击。 之前经常被问到的原因是仍然没有可行的解决方案。但是,我看到Google Docs现在实际上有一个适用于键盘事件和按钮的工作解决方案。所以,这是可能的,但他们是如何做到的? Software Salad文章Accessing the System Clipboard with JavaScript – A Holy Grail?给出了一个很好的问题概述(但它已经有几年了)。

简而言之:

  • 您可以使用键盘事件ctrl + x,ctrl + c,ctrl + v来复制带有准备数据的隐藏文本区域中的文本,或者在隐藏字段中捕获粘贴文本然后使用它执行某些操作

  • 您可以通过Flash或Java Applet将某些内容复制到系统剪贴板,而无需用户批准。

  • 你可以使用一个“真实”的解决方案,其中包含用于IE的clipboardData.setData和用于其他浏览器的execCommand,这取决于用户的认可。

知道Google如何解决剪贴板问题吗?

5 个答案:

答案 0 :(得分:25)

我知道很久以前就发布了这个问题,但是我需要检查谷歌是如何做到这一点的,所以也许有人会觉得这个问题很有用。

实际上谷歌也使用系统剪贴板,但它有点棘手。如果您使用键盘快捷方式,您可以捕获复制/粘贴/剪切事件,例如窗口:

window.addEventListener('copy', function (ev) {
    console.log('copy event');
    // you can set clipboard data here, e.g.
    ev.clipboardData.setData('text/plain', 'some text pushed to clipboard');
    // you need to prevent default behaviour here, otherwise browser will overwrite your content with currently selected 
    ev.preventDefault();
});

键盘快捷键的实例:http://jsfiddle.net/tyk9U/

不幸的是,这只是键盘快捷键的解决方案,并且上下文菜单存在问题,因为如果没有本机(可信)复制/剪切/粘贴事件,您将无法访问剪贴板数据。但谷歌做了有趣的伎俩。 API document.execCommand()允许您运行contenteditable元素的命令,并且命令'copy'可以通过document.execCommand('copy')触发它。但是当您在Chrome中的控制台中尝试此操作时,它将返回false。我花了一些时间来调查这一点,结果发现他们安装了Chrome扩展程序,名为“Google云端硬盘”(转到chrome:// apps /,你可以在那里看到它),可以为域名drive.google启用剪贴板访问。 com和docs.google.com。打开一些文档或电子表格并输入控制台document.execCommand('copy') - 它将返回true。卸载扩展时,您将无法使用上下文菜单中的剪贴板操作。

您可以使用非常简单的清单文件为此自行创建此类应用程序(详情请参见https://developer.chrome.com/apps/first_app):

{
    "manifest_version": 2,
    "name": "App name",
    "description": "App description",
    "version": "1.0",
    "app": {
        "urls": [
            "http://your.app.url.here/"
        ],
        "launch": {
            "web_url": "http://your.app.url.here/"
        }
    },
    "icons": {
        "128": "x-128.png"
    },
    "permissions": [
        "clipboardRead",
        "clipboardWrite"
    ]
}

“权限”字段可启用剪贴板操作。

现在,当您启用此功能后,您可以执行document.execCommand('copy')并且它将起作用(将返回true)。但这不是一切 - 铬触发器复制事件中的document.execCommand('copy'),您可以使用与捕获键盘剪贴板快捷方式相同的代码来捕获它。这就是Google现在做到的。

当然,此说明仅适用于Chrome。

答案 1 :(得分:10)

[注意:此答案在撰写时准确无误,并正确回答了OP的问题。但是,技术从那时起就发生了变化;如果您有兴趣在您的网络应用程序中支持复制和粘贴,请在此页面上查看其他更近期的答案。 -ruakh]


  

但是,我看到Google Docs现在实际上有一个适用于键盘事件和按钮的工作解决方案。

不,它没有。并不是的。对于键盘事件,Google Docs不做任何事情;它根本不会阻止浏览器的默认复制粘贴功能;因此,用户可以自由地复制和粘贴,而不会影响Google Docs。对于按钮,Google文档不支持系统剪贴板,但它自己的“网络剪贴板”完全在Google文档中。您无法使用工具栏按钮将文本复制粘贴到计算机上的其他程序中,也无法粘贴从计算机上的其他程序复制的文本。

有关此内容的详细信息,请参阅"Copying and pasting in Google Docs"。 (这是面向用户的,而不是面向开发人员的,但它确实可以很好地明确什么是支持和不支持。)

答案 2 :(得分:4)

作为对其他人已在此主题中发布的内容的补充,我创建了一个完整的工作示例,演示了键盘快捷方式(Mac OS X上的CTRL + C或CMD + C)以及自定义按钮方法,它触发了复制行动。

可在此处找到完整演示:http://jsfiddle.net/rve7d/

我发现Mateusz W在尝试创建此演示时非常有用,但他没有考虑对IE的支持,IE的行为略有不同,并使用不同的数据类型作为第一个参数。

if(window.clipboardData) {
    // use just 'Text' or 'Url' as a first param otherwise strange exception is thrown
    window.clipboardData.setData('Text', 'Text that will be copied to CB');        
} else if(ev.originalEvent.clipboardData) {
    ev.originalEvent.clipboardData.setData('text/plain', 'Text that will be copied to CB');      
} else {
    alert('Clipboard Data are not supported in this browser. Sorry.');
}

PS:我的自定义电子表格视图组件需要此功能,并且在分析Google Spreadsheets的源代码时,我的解决方案大多符合他们的解决方案。

答案 3 :(得分:3)

谷歌使用一种非常简单但很酷的方法。通过使用firebug,你将会知道加载的html代码有一个大小为1的文本区域.Google doc所做的是,当用户选择文本并按下ctrl + c时,它会捕获事件并通过某种技术获取在doc容器中选择的文本,并将文本区域的值设置为该内容。比它集中并选择文本区域。现在它释放ctrl + c事件。但现在文本在文本区域中被选中,因此当事件被重新发布时,浏览器会复制文本区域中的文本,从而获得复制的文本

答案 4 :(得分:0)

<p>COPY : </p>
<p>Email me at <a class="js-emaillink" href="mailto:matt@example.co.uk">matt@example.co.uk</a></p>
<p><button class="js-emailcopybtn" value="clipboard" >clipboard</button></p>
<textarea rows="10" cols = "12"></textarea>
<p>CUT: </p>
<p><textarea class="js-cuttextarea">Hello I'm some text</textarea></p>
<p><button class="js-textareacutbtn" disable>Cut Textarea</button></p>
<script>
//copy clipboard
var copyEmailBtn = document.querySelector('.js-emailcopybtn');
copyEmailBtn.addEventListener('click', function(event) {
  // Выборка ссылки с электронной почтой
  var emailLink = document.querySelector('.js-emaillink');
  var range = document.createRange();
  range.selectNode(emailLink);
  window.getSelection().addRange(range);
  try {
    // Теперь, когда мы выбрали текст ссылки, выполним команду копирования
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copy email command was ' + msg);
  } catch(err) {
    console.log('Oops, unable to copy');
  }
  // Снятие выделения - ВНИМАНИЕ: вы должны использовать
  // removeRange(range) когда это возможно
  window.getSelection().removeAllRanges();
});
//cut
var cutTextareaBtn = document.querySelector('.js-textareacutbtn');
cutTextareaBtn.addEventListener('click', function(event) {
  var cutTextarea = document.querySelector('.js-cuttextarea');
  cutTextarea.select();
  try {
    var successful = document.execCommand('cut');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Cutting text command was ' + msg);
  } catch(err) {
    console.log('Oops, unable to cut');
  }
});
</script>