Javascript - 将字符串作为文本/html 复制到剪贴板

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34191780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:02:03  来源:igfitidea点击:

Javascript - Copy string to clipboard as text/html

javascriptclipboard

提问by kofifus

Is there a way in javascript to copy an html string (ie <b>xx<b>) into the clipboard as text/html, so that it can then be pasted into for example a gmail message with the formatting (ie, xx in bold)

在javascript中有没有办法将html字符串(即<b>xx<b>)作为文本/html复制到剪贴板中,以便然后可以将其粘贴到例如具有格式(即粗体xx)的gmail消息中

There exists solutions to copy to the clipboard as text (text/plain) for example https://stackoverflow.com/a/30810322/460084but not as text/html

存在将文本(文本/纯文本)复制到剪贴板的解决方案,例如https://stackoverflow.com/a/30810322/460084但不是文本/html

I need a non flash, non jquery solution that will work at least on IE11 FF42 and Chrome.

我需要一个非 Flash、非 jquery 解决方案,它至少可以在 IE11 FF42 和 Chrome 上运行。

Ideally I would like to store both text and html versions of the string in the clipboard so that the right one can be pasted depending if the target supports html or not.

理想情况下,我想在剪贴板中存储字符串的文本和 html 版本,以便可以根据目标是否支持 html 粘贴正确的版本。

采纳答案by kofifus

I have done a few modifications on Loilo's answer above:

我对上面 Loilo 的回答做了一些修改:

  • setting (and later restoring) the focus to the hidden div prevents FF going into endless recursion when copying from a textarea

  • setting the range to the inner children of the div prevents chrome inserting an extra <br>in the beginning

  • removeAllRanges on getSelection() prevents appending to existing selection (possibly not needed)

  • try/catch around execCommand

  • hiding the copy div better

  • 设置(并稍后恢复)焦点到隐藏的 div 防止 FF 在从 textarea 复制时进入无限递归

  • 将范围设置为 div 的内部子级可防止 chrome<br>在开头插入额外的内容

  • getSelection() 上的 removeAllRanges 防止附加到现有选择(可能不需要)

  • 尝试/抓住 execCommand

  • 更好地隐藏复制div

On OSX this will not work. Safari does not support execCommand and chrome OSX has a known bug https://bugs.chromium.org/p/chromium/issues/detail?id=552975

在 OSX 上,这将不起作用。Safari 不支持 execCommand 并且 chrome OSX 有一个已知错误https://bugs.chromium.org/p/chromium/issues/detail?id=552975

code:

代码:

clipboardDiv = document.createElement('div');
clipboardDiv.style.fontSize = '12pt'; // Prevent zooming on iOS
// Reset box model
clipboardDiv.style.border = '0';
clipboardDiv.style.padding = '0';
clipboardDiv.style.margin = '0';
// Move element out of screen 
clipboardDiv.style.position = 'fixed';
clipboardDiv.style['right'] = '-9999px';
clipboardDiv.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
// more hiding
clipboardDiv.setAttribute('readonly', '');
clipboardDiv.style.opacity = 0;
clipboardDiv.style.pointerEvents = 'none';
clipboardDiv.style.zIndex = -1;
clipboardDiv.setAttribute('tabindex', '0'); // so it can be focused
clipboardDiv.innerHTML = '';
document.body.appendChild(clipboardDiv);

function copyHtmlToClipboard(html) {
  clipboardDiv.innerHTML=html;

  var focused=document.activeElement;
  clipboardDiv.focus();

  window.getSelection().removeAllRanges();  
  var range = document.createRange(); 
  range.setStartBefore(clipboardDiv.firstChild);
  range.setEndAfter(clipboardDiv.lastChild);
  window.getSelection().addRange(range);  

  var ok=false;
  try {
     if (document.execCommand('copy')) ok=true; else utils.log('execCommand returned false !');
  } catch (err) {
     utils.log('execCommand failed ! exception '+err);
  }

  focused.focus();
}

see jsfiddlewhere you can enter html segment into the textarea and copy to the clipboard with ctrl+c.

请参阅jsfiddle,您可以在其中将 html 段输入 textarea 并使用 ctrl+c 复制到剪贴板。

回答by Loilo

Since this answer has gotten some attention, I have completely rewritten the messy original to be easier to grasp. If you want to look at the pre-revisioned version, you can find it here.

由于这个答案引起了一些关注,我将凌乱的原文完全重写为更容易理解。如果您想查看预修订版本,可以在此处找到。



The boiled down question:

归结起来的问题:

Can I use JavaScript to copy the formatted output of some HTML code to the users clipboard?

我可以使用 JavaScript 将某些 HTML 代码的格式化输出复制到用户剪贴板吗?



Answer:

回答:

Yes, with some limitations, you can.

是的,有一些限制,你可以。



Solution:

解决方案:

Below is a function that will do exactly that. I tested it with your required browsers, it works in all of them. However, IE 11 will ask for confirmation on that action.

下面是一个可以做到这一点的函数。我使用您所需的浏览器对其进行了测试,它适用于所有浏览器。但是,IE 11 将要求对该操作进行确认。

Explanation how this works can be found below, you may interactively test the function out in this jsFiddle.

可以在下面找到有关其工作原理的说明,您可以在此jsFiddle 中以交互方式测试该功能。

// This function expects an HTML string and copies it as rich text.

function copyFormatted (html) {
  // Create container for the HTML
  // [1]
  var container = document.createElement('div')
  container.innerHTML = html

  // Hide element
  // [2]
  container.style.position = 'fixed'
  container.style.pointerEvents = 'none'
  container.style.opacity = 0

  // Detect all style sheets of the page
  var activeSheets = Array.prototype.slice.call(document.styleSheets)
    .filter(function (sheet) {
      return !sheet.disabled
    })

  // Mount the container to the DOM to make `contentWindow` available
  // [3]
  document.body.appendChild(container)

  // Copy to clipboard
  // [4]
  window.getSelection().removeAllRanges()

  var range = document.createRange()
  range.selectNode(container)
  window.getSelection().addRange(range)

  // [5.1]
  document.execCommand('copy')

  // [5.2]
  for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = true

  // [5.3]
  document.execCommand('copy')

  // [5.4]
  for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = false

  // Remove the container
  // [6]
  document.body.removeChild(container)
}


Explanation:

解释:

Look into the comments in the code above to see where you currently are in the following process:

查看上面代码中的注释,了解您当前在以下过程中的位置:

  1. We create a container to put our HTML code into.
  2. We style the container to be hidden and detect the page's active stylesheets. The reason will be explained shortly.
  3. We put the container into the page's DOM.
  4. We remove possibly existing selections and select the contents of our container.
  5. We do the copying itself. This is actually a multi-step process: Chrome will copy text as it sees it, with applied CSS styles, while other browsers will copy it with the browser's default styles. Therefore we will disable all user styles before copying to get the most consistent result possible.

    1. Before we do this, we prematurely execute the copycommand. This is a hack for IE11: In this browser, the copying must be manually confirmed once. Until the user clicked the "Confirm" button, IE users would see the page without any styles. To avoid this, we copy first, wait for confirmation, then disable the styles and copy again. That time we won't get a confirmation dialog since IE remembers our last choice.
    2. We actually disable the page's styles.
    3. Now we execute the copycommand again.
    4. We re-enable the stylesheets.
  6. We remove the container from the page's DOM.
  1. 我们创建一个容器来放入我们的 HTML 代码。
  2. 我们将容器设置为隐藏的样式并检测页面的活动样式表。稍后将解释原因。
  3. 我们将容器放入页面的 DOM 中。
  4. 我们删除可能存在的选择并选择我们容器的内容。
  5. 我们自己进行复制。这实际上是一个多步骤的过程:Chrome 将复制它看到的文本并应用 CSS 样式,而其他浏览器将使用浏览器的默认样式复制它。因此,我们将在复制之前禁用所有用户样式,以获得尽可能一致的结果。

    1. 在我们这样做之前,我们过早地执行copy命令。这是 IE11 的一个 hack:在这个浏览器中,复制必须手动确认一次。直到用户单击“确认”按钮,IE 用户才会看到没有任何样式的页面。为了避免这种情况,我们先复制,等待确认,然后禁用样式并再次复制。那时我们不会收到确认对话框,因为 IE 会记住我们的最后选择。
    2. 我们实际上禁用了页面的样式。
    3. 现在我们copy再次执行命令。
    4. 我们重新启用样式表。
  6. 我们从页面的 DOM 中移除容器。

And we're done.

我们已经完成了。



Caveats:

注意事项:

  • The formatted content will not be perfectly consistent across browsers.

    As explained above, Chrome (i.e. the Blink engine) will use a different strategy than Firefox and IE: Chrome will copy the contents with their CSS styling, but omitting any styles that are not defined.

    Firefox and IE on the other hand won't apply page-specific CSS, they will apply the browser's default styles. This also means they will have some weird styles applied to them, e.g. the default font (which is usually Times New Roman).

  • For security reasons, browsers will only allow the function to execute as an effect of a user interaction (e.g. a click, keypress etc.)

  • 格式化的内容在浏览器之间不会完全一致。

    如上所述,Chrome(即 Blink 引擎)将使用与 Firefox 和 IE 不同的策略:Chrome 将使用其 CSS 样式复制内容,但省略任何未定义的样式。

    另一方面,Firefox 和 IE 不会应用特定于页面的 CSS,它们将应用浏览器的默认样式。这也意味着它们将应用一些奇怪的样式,例如默认字体(通常是Times New Roman)。

  • 出于安全原因,浏览器将只允许该功能作为用户交互(例如点击、按键等)的效果执行。

回答by Theo

There is a much simpler solution. Copy a section of your page (element) than copying HTML.

有一个更简单的解决方案。复制页面(元素)的一部分而不是复制 HTML。

With this simple function you can copy whatever you want (text, images, tables, etc.) on your page or the whole document to the clipboard. The function receives the element idor the elementitself.

使用这个简单的功能,您可以将页面或整个文档上的任何内容(文本、图像、表格等)复制到剪贴板。该函数接收元素id元素本身。

function copyElementToClipboard(element) {
  window.getSelection().removeAllRanges();
  let range = document.createRange();
  range.selectNode(typeof element === 'string' ? document.getElementById(element) : element);
  window.getSelection().addRange(range);
  document.execCommand('copy');
  window.getSelection().removeAllRanges();
}

How to use:

如何使用:

copyElementToClipboard(document.body);
copyElementToClipboard('myImageId');