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

IT技术 javascript copy clipboard paste
2021-03-03 16:57:25

是的,这个问题已经被反复问到:如何使用javascript从系统剪贴板复制和粘贴到系统剪贴板?到目前为止,我只找到了部分解决方案和技巧。过去经常被问到的原因是仍然没有可行的解决方案。但是,我看到 Google Docs 现在实际上有一个适用于键盘事件和按钮的解决方案。所以,这是可能的,但他们怎么做呢?软件沙拉文章,使用 JavaScript 访问系统剪贴板 – 圣杯?,很好地概述了这个问题(但它已经有几年了)。

简而言之:

  • 您可以使用键盘事件 ctrl+x、ctrl+c、ctrl+v 从带有准备好的数据的隐藏文本区域复制文本,或者在隐藏字段中捕获粘贴的文本,然后对其进行处理

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

  • 您可以使用带有用于 IE 的 clipboardData.setData 和用于其他浏览器的 execCommand 的“真实”解决方案,这取决于用户的批准。

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

5个回答

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

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

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/

不幸的是,这只是键盘快捷键的解决方案,上下文菜单存在问题,因为如果没有本机(受信任的)复制/剪切/粘贴事件,您将无法访问剪贴板数据。但谷歌做了有趣的把戏。有 APIdocument.execCommand()允许您为 contenteditable 元素运行命令,还有命令“复制”,您可以通过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"
    ]
}

此处的“权限”字段启用剪贴板操作。

现在,当您启用此功能时,您可以执行此操作document.execCommand('copy')并且它将起作用(将返回true)。但这并不是全部 -document.execCommand('copy')在 chrome 中触发复制事件,您可以使用用于捕获键盘剪贴板快捷方式的相同代码来捕获它。这是现在谷歌做到的。

当然,这个描述只对 Chrome 有效。

我试图测试这个答案并意识到我无法简单地通过禁用 chrome 扩展来重现。我不得不完全卸载它。作为另一点。您可以运行 document.execCommand('copy') 只要它运行以响应有效的用户单击事件。不过,我一直无法弄清楚您是否可以自己捕获该事件。你知道你是否必须有一个扩展来捕获由 document.execCommand('copy') 触发的 ClipBoardEvent?规范让我相信 execCommand 实现没有触发事件。
2021-04-22 16:57:25
@JasonT。最近发生了变化 - 看看这里developers.google.com/web/updates/2015/04/cut-and-copy-commands
2021-05-09 16:57:25

[注意:此答案在撰写时是准确的,并正确回答了 OP 的问题。然而,从那时起,技术不断发展。如果您有兴趣在您的网络应用程序中支持复制和粘贴,请参阅此页面上的其他最新答案。- ruak]


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

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

有关这方面的更多信息,请参阅“在 Google 文档中复制和粘贴”(这是面向用户的而不是面向开发人员的,但它在明​​确支持和不支持的方面做得很好。)

啊哈,现在我明白了。谷歌创建了一个“网络剪贴板”,它允许您从任何浏览器窗口复制/粘贴到任何浏览器窗口。因此,您不使用系统剪贴板,而是使用与您的帐户相关联的网络剪贴板。谢谢。
2021-04-21 16:57:25
@ruakh 你在这里并不完全正确。尝试使用按钮(不是键盘)从谷歌文档中复制一些文本并将其粘贴到其他应用程序中 - 它可以工作。文本被复制到系统剪贴板(您也可以安装某种剪贴板查看器来查看它是否正确)。看看我下面的回复 - 他们使用 Chrome 中默认安装的 Chrome 扩展程序,这样他们就可以读取和写入系统剪贴板。
2021-04-29 16:57:25
这个答案只是帮助我帮助试图从 MS Excel 复制“n”粘贴到 Google 电子表格的人。谢谢 :-)
2021-05-04 16:57:25
@JosdeJong:是的,正是。:-)
2021-05-11 16:57:25
@MateuszW:我的回答来自将近一年半以前。我相信当时它是准确的;请注意,我链接到的帮助页面现在已更改为“您可以使用键盘快捷键 [...]”,但在我发布答案时并非如此。
2021-05-13 16:57:25

作为对其他人已经在此线程中发布的内容的补充,我创建了一个完整的示例,演示了键盘快捷键方法(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 电子表格的源代码的过程中,我的解决方案大多符合他们的解决方案。

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

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