簡體   English   中英

Javascript - 將字符串作為文本/html 復制到剪貼板

[英]Javascript - Copy string to clipboard as text/html

在 javascript 中有沒有辦法將 html 字符串(即<b>xx<b> )作為文本/html 復制到剪貼板中,以便然后可以將其粘貼到例如具有格式的 gmail 消息中(即 xx 在膽大)

存在將文本(文本/純文本)復制到剪貼板的解決方案,例如https://stackoverflow.com/a/30810322/460084但不是文本/html

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

理想情況下,我想在剪貼板中存儲字符串的文本和 html 版本,以便可以根據目標是否支持 html 粘貼正確的版本。

由於這個答案引起了一些關注,我將凌亂的原文完全重寫為更容易理解。 如果您想查看預修訂版本,可以在此處找到。


歸結起來的問題:

我可以使用 JavaScript 將某些 HTML 代碼的格式化輸出復制到用戶剪貼板嗎?


回答:

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


解決方案:

下面是一個可以做到這一點的函數。 我使用您所需的瀏覽器對其進行了測試,它適用於所有瀏覽器。 但是,IE 11 將要求對該操作進行確認。

可以在下面找到有關其工作原理的說明,您可以在此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)
}

解釋:

查看上面代碼中的注釋,了解您當前在以下過程中的位置:

  1. 我們創建一個容器來放入我們的 HTML 代碼。
  2. 我們將容器設置為隱藏的樣式並檢測頁面的活動樣式表。 稍后將解釋原因。
  3. 我們將容器放入頁面的 DOM 中。
  4. 我們刪除可能存在的選擇並選擇我們容器的內容。
  5. 我們自己進行復制。 這實際上是一個多步驟的過程:Chrome 將復制它看到的文本並應用 CSS 樣式,而其他瀏覽器將使用瀏覽器的默認樣式復制它。 因此,我們將在復制之前禁用所有用戶樣式,以獲得盡可能一致的結果。

    1. 在我們這樣做之前,我們過早地執行了copy命令。 這是 IE11 的一個 hack:在這個瀏覽器中,復制必須手動確認一次。 直到用戶單擊“確認”按鈕,IE 用戶才會看到沒有任何樣式的頁面。 為了避免這種情況,我們先復制,等待確認,然后禁用樣式並再次復制。 那時我們不會收到確認對話框,因為 IE 會記住我們的最后選擇。
    2. 我們實際上禁用了頁面的樣式。
    3. 現在我們再次執行copy命令。
    4. 我們重新啟用樣式表。
  6. 我們從頁面的 DOM 中移除容器。

我們已經完成了。


注意事項:

  • 格式化的內容在瀏覽器之間不會完全一致。

    如上所述,Chrome(即 Blink 引擎)將使用與 Firefox 和 IE 不同的策略:Chrome 將使用其 CSS 樣式復制內容,但省略任何未定義的樣式。

    另一方面,Firefox 和 IE 不會應用特定於頁面的 CSS,它們將應用瀏覽器的默認樣式。 這也意味着它們將應用一些奇怪的樣式,例如默認字體(通常是Times New Roman )。

  • 出於安全原因,瀏覽器將只允許該功能作為用戶交互(例如點擊、按鍵等)的效果執行。

有一個更簡單的解決方案。 復制頁面(元素)的一部分而不是復制 HTML。

使用這個簡單的功能,您可以將頁面或整個文檔上的任何內容(文本、圖像、表格等)復制到剪貼板。 該函數接收元素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();
}

如何使用:

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

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

  • 設置(並稍后恢復)焦點到隱藏的 div 防止 FF 在從 textarea 復制時進入無限遞歸

  • 將范圍設置為 div 的內部子級可防止 chrome 在開頭插入額外的<br>

  • getSelection() 上的 removeAllRanges 防止附加到現有選擇(可能不需要)

  • 嘗試/抓住 execCommand

  • 更好地隱藏復制 div

在 OSX 上,這將不起作用。 Safari 不支持 execCommand 並且 chrome OSX 有一個已知錯誤https://bugs.chromium.org/p/chromium/issues/detail?id=552975

代碼:

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();
}

請參閱jsfiddle ,您可以在其中將 html 段輸入 textarea 並使用 ctrl+c 復制到剪貼板。

如果要使用新的Clipboard API ,請使用如下所示的write方法

var type = "text/html";
var blob = new Blob([text], { type });
var data = [new ClipboardItem({ [type]: blob })];

navigator.clipboard.write(data).then(
    function () {
    /* success */
    },
    function () {
    /* failure */
    }
);

當前(2021 年 9 月),問題是Firefox 不支持此方法

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM