JavaScript如何实现剪切/复制/粘贴到剪贴板?Google是如何解决的?

26

这个问题一再被提出:如何使用JavaScript从系统剪贴板复制和粘贴?到目前为止,我只找到了部分解决方案和技巧。

过去这个问题一再被提出的原因是还没有可行的解决方案。然而,我发现Google Docs现在实际上已经有了针对键盘事件和按钮的可行解决方案。所以,这是可能的,但他们是如何做到的呢?《Software Salad》文章,使用JavaScript访问系统剪贴板 - 圣杯?,给出了该问题的一个不错的概述(但它是几年前的)。

简而言之:

  • 你可以使用键盘事件ctrl + x、ctrl + c、ctrl + v,从隐藏的具有准备数据的文本区域中复制文本,或者捕捉粘贴的文本在一个隐藏的字段中,然后对其进行操作。

  • 你可以通过Flash或者Java Applet的某些技巧将东西复制到系统剪贴板中,而无需得到用户的批准。

  • 你可以使用"真正"的解决方案,即对于IE使用clipboardData.setData,对于其他浏览器使用execCommand,这取决于用户的批准。

你有什么想法,Google是如何解决剪贴板问题的吗?


你使用的是哪个浏览器?在Chrome中,当我使用菜单中的复制/粘贴时,至少会出现这个错误:http://imgur.com/8L5CR 这又意味着他们还没有解决这个问题。 - Niklas
你是对的,现在我明白他们不使用系统剪贴板(除了常规键事件),而是创建了一个与您的帐户相关联的Web剪贴板。 - Jos de Jong
5个回答

27

我知道这个问题早就被发布了,但是我需要检查一下谷歌是如何做到的,也许有人会发现这很有用。

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

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/

不幸的是,这只是针对键盘快捷键的解决方案,而在上下文菜单中存在问题,因为您无法在没有本地(受信任的)复制/剪切/粘贴事件的情况下访问剪贴板数据。但是,Google使用了一个有趣的技巧。有一个API document.execCommand(),允许您为可编辑元素运行命令,并且有一个名为“copy”的命令,您可以通过document.execCommand('copy')触发它。但是,当您尝试在Chrome控制台中执行此操作时,它将返回false。我花了一些时间进行调查,结果发现他们安装了Chrome扩展程序,称为“Google Drive”(转到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"
    ]
}

"permissions"字段在这里开启剪贴板操作。

现在当你启用了它,你可以执行document.execCommand('copy')并且它会起作用(返回true)。但这还不是全部-在Chrome中执行document.execCommand('copy')会触发复制事件,你可以使用与捕获键盘剪贴板快捷键相同的代码来捕获它。这就是Google的做法。

当然,这个描述只适用于Chrome。


1
我试图测试这个答案,但发现仅通过禁用Chrome扩展无法复现。我必须完全卸载它。另外,只要在响应有效的用户单击事件时运行document.execCommand('copy'),就可以运行它。但我一直没能弄清楚是否可以自己捕获该事件。您知道是否需要扩展程序来捕获由document.execCommand('copy')触发的ClipBoardEvent吗?规范让我相信execCommand实现不会触发事件。 - Jason T.
@JasonT,最近有所变化 - 在这里看一下 https://developers.google.com/web/updates/2015/04/cut-and-copy-commands - Mateusz W

12

[注意: 此回答在撰写时是准确的,正确回答了提问者的问题。 但是,技术已经发展,如果您有兴趣支持Web应用程序中的复制和粘贴,请参见本页面上其他更近期的回答。 —ruakh]


然而,我看到谷歌文档现在实际上已经有了解决方案,既适用于键盘事件,也适用于按钮。

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

有关更多信息,请参见“在谷歌文档中复制和粘贴”。 (这是面向用户而非开发人员的,但它做了一个不错的工作,清楚地说明了什么是受支持的,什么是不受支持的。)


3
啊哈,现在我明白了。谷歌创建了一个"网络剪贴板",允许你从任何浏览器窗口复制/粘贴到任何浏览器窗口。因此,你不使用系统剪贴板,而是使用与你的帐户相结合的网络剪贴板。谢谢。 - Jos de Jong
1
@MateuszW:我的回答是一年半以前的。我相信当时它是准确的;请注意,我链接的帮助页面现在已经更改为“您可以使用键盘快捷方式[...]”,而我发布答案时并非如此。 - ruakh
我在Chrome中禁用了所有浏览器扩展,但一些Google Doc菜单按钮仍然可以使用系统复制/粘贴。此外,我可以打开控制台运行document.execCommand('copy')并返回true。即使在无痕模式下,没有授权任何扩展...结果也是一样的。 - Ecropolis
是的,我可以在MSPaint中复制位图,并使用右键自定义上下文菜单将其粘贴到Google文档中。因此,这个答案不再准确。 - Tomas M
FYI更新:Web剪贴板将于2017年9月13日被删除。https://gsuiteupdates.googleblog.com/2017/05/web-clipboard-to-be-removed-from-google.html - Malik A. Rumi
显示剩余3条评论

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电子表格的源代码之后,我的解决方案大部分符合他们的解决方案。


3
谷歌使用的是一种非常简单但很酷的方法。通过使用firebug,您将了解到所加载的html代码中有一个大小为1的文本区域。谷歌文档所做的就是当用户选择文本并按下ctrl+c时,它捕获事件,并通过某些技术获取选定的文本内容,并将文本区域的值设置为该内容。然后它会聚焦并选择文本区域。现在它释放ctrl+c事件。但现在文本已经被选择在文本区域中,所以当事件被释放时,浏览器会复制文本区域中的文本,从而我们得到了复制的文本。

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>

请勿重复链接 https://developers.google.com/web/updates/2015/04/cut-and-copy-commands。 - centurian

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