web-dev-qa-db-ja.com

Javascript-文字列をtext / htmlとしてクリップボードにコピーします

Javascriptでhtml文字列をコピーする方法はありますか(つまり、<b>xx<b>)クリップボードにtext/htmlとして挿入します。これにより、たとえば書式設定(つまり、xxは太字)でGmailメッセージに貼り付けることができます。

たとえば https://stackoverflow.com/a/30810322/460084 としてではなくtext/htmlとしてではなく、テキスト(text/plain)としてクリップボードにコピーするソリューションがあります。

少なくともIE11 FF42とChromeで動作する非フラッシュ、非jqueryソリューションが必要です。

理想的には、テキストとHTMLの両方のバージョンの文字列をクリップボードに保存して、ターゲットがhtmlをサポートしているかどうかに応じて正しいものを貼り付けることができるようにします。

22
kofifus

上記のLoiloの答えにいくつか修正を加えました。

  • 非表示のdivにフォーカスを設定(および後で復元)することで、textareaからコピーするときにFFが無限に再帰しないようにします

  • 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でクリップボードにコピーできます。

4
kofifus

この答えは注目を集めているため、乱雑なオリジナルを完全に書き直し、把握しやすくしました。事前に修正されたバージョンを見たい場合は、それを見つけることができます here


煮詰められた質問:

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のハックです。このブラウザーでは、コピーを手動で1回確認する必要があります。ユーザーが[確認]ボタンをクリックするまで、IEユーザーはスタイルなしでページを表示します。これを回避するために、まずコピーし、確認を待ってからスタイルを無効にして再度コピーします。 IEは最後の選択を記憶しているため、確認ダイアログは表示されません。
    2. 実際にページのスタイルを無効にします。
    3. 次に、copyコマンドを再度実行します。
    4. スタイルシートを再度有効にします。
  6. ページのDOMからコンテナを削除します。

これで完了です。


警告:

  • フォーマットされたコンテンツは、ブラウザー間で完全に一貫していません。

    上記で説明したように、Chrome(つまりBlinkエンジン)はFirefoxおよびIEとは異なる戦略を使用します。ChromeはCSSスタイルでコンテンツをコピーしますが、定義されていないスタイルを省略します。

    FirefoxとIEはページ固有のCSSを適用せず、ブラウザのデフォルトスタイルを適用します。これは、デフォルトフォントなどの奇妙なスタイルが適用されることも意味します(通常は Times New Roman です)。

  • セキュリティ上の理由により、ブラウザはユーザーの操作(クリック、キー押下など)の結果としてのみ機能を実行することを許可します

27
Loilo