#054
posted on 2021.09.30

JavaScriptで任意のテキストをデバイスのクリップボードにコピーする方法。

ページのタイトルやURLなどをコピーするボタンの挙動の詳細が知りたかったので、JavaScriptで任意のテキストをデバイスのシステムクリップボードにコピーの実装方法のメモ。

 

JavaScriptでクリップボードにコピーする方法は以下の3つ。

  • 方法1 : Clipboard APIを使う。 (SSL通信のサイトでのみ利用可能。IEは非対応。)
  • 方法2 : IE独自仕様のwindow.clipboardDataを使う。(IEで対応する場合。)
  • 方法3 : execCommand()メソッドを使う。(現在は廃止されているメソッド。非SSLサイトで対応する場合。)

 

クリップボードとは、短期間のデータ格納や転送のために使われるバッファであり、文書やアプリケーションの間で使われます。
これは、通常名前のない一時的なバッファとして実装され、貼り付けバッファと呼ばれることもあり、その環境で定義されたアプリケーションプログラムインターフェイスを使うことで、ほとんど全てのプログラムがアクセスすることができます。

(MDN Web Docs)

 

 

Clipboard APIを使う方法

Clipboard APIのmozillaの公式ドキュメント

 

Clipboard APIの要約

  • Clipboard APIは、execCommand()メソッドの代替として設計されたもの。
  • SSL(Secure Sockets Layer)のサイトでのみ利用可能。(非SSLサイトではclipboardオブジェクトにアクセスできない。)
  • IEは非対応。
  • ユーザーが許可している場合、システムクリップボードにアクセスして読み取りや書き込みを行う機能を提供する。
  • Clipboard APIは、ユーザーエージェントの情報を保持しているNavigatorインターフェイスに読み取り専用のclipboardプロパティーを追加し、clipboardオブジェクトを返す。
  • clipboardオブジェクトのメソッドでシステムクリップボードにアクセスができる。
  • Clipboard APIのすべてのメソッドは非同期で動作するので、クリップボードにアクセスできた場合にPromiseオブジェクトを返す。(コピーなど指定の処理が完了した段階で次の処理をしたい場合に使用。)
  • clipboardオブジェクトは、navigatorオブジェクトが持つclipboardプロパティーで参照できる。
  • navigatorオブジェクトは、windowオブジェクトが持つnavigatorプロパティーで参照できる。(Webブラウザ上でwindowオブジェクトはグローバルオブジェクトなので、「window.」は省略できる。)

※ 非SSLの開発環境で動作したので、localhostなどのループバックアドレスなら非SSLでも利用できると思われるが、公式ドキュメントから情報が見つけられないので詳細不明。

 

[ clipboardオブジェクトが持つ主なメソッド ]

メソッド 動作内容
read() クリップボードから任意のデータ(画像など)を要求し、{jsxref(“Promise”)}}を返す。(デフォルトでは無効。)
readText() システムクリップボードからテキストを要求する。クリップボードにテキストが無ければ空文字列を返す。
write() システムクリップボードに任意のデータを書き込む。(デフォルトでは無効。)
writeText() システムクリップボードにテキストを書き込む。

 

システムクリップボードへのアクセス権限

  • ユーザーがクリップボードへのアクセスを許可しているかはPermissions APIによって確認できるが、現状Permissions APIの実装内容がブラウザによって違うようなので実用性は不明。
  • もし「”clipboard-read”」や「”clipboard-write”」の権限が与えられていなければ、clipboardオブジェクトのメソッド呼び出しはできない。(現状、Permissions APIの実装内容がブラウザで異なるので詳細は未検証。)

※ Permissions APIについてのmozillaの公式ドキュメント

 

JavaScriptでクリップボードにコピーの実装

「コピーする」ボタンをクリックしたら、任意のid属性(ここでは「txt-copy」)を指定しているHTML要素が内包するテキストをクリップボードにコピーする挙動をJavaScriptで実装。

 

1. HTMLのマークアップ

コピーするテキスト内容をユーザーが直接編集できるようにcontenteditable属性を付加しておく。

※ contenteditable属性がtrueの要素は、ブラウザ上で内容を編集できる。

<p id="txt-copy" contenteditable="true">クリップボードにコピーしたいテキストの本文。</p>
<div id="btn-copy">コピーする</div>

2. Clipboard APIでクリップボードにコピーを実行

「クリップボードへのコピーを実行する関数」を作成して、「コピーする」ボタンのクリックイベントで実行する。

  • ブラウザの対応状況で処理を変えるので、各オブジェクトのプロパティーが存在するかを判定して分岐。
  • コピーする要素をgetElementById()メソッドで取得したままだとElementオブジェクトであることを表す文字列がコピーされてしまうので、innerHTMLプロパティーを参照して、要素の子孫を文字列(DOMString)として取得する。(ターゲットとなる要素タグ自身も含める場合はouterHTMLを使う。)
  • ユーザーにコピー完了を伝えるメッセージなどを表示したい場合は、then()メソッド内で処理。
//クリップボードにコピーを実行する関数を作成
function ag2copy(){
  //コピーしたいテキストを持つ要素を取得
  let targetEle = document.getElementById('txt-copy');

  //ブラウザの対応状況で分岐
  if(navigator.clipboard){
    //クリップボードにコピーを実行
    navigator.clipboard.writeText(targetEle.innerHTML).then(function(){
      //コピーに成功したときの処理...
      console.log('copied.');
    },function(){
      //コピーに失敗したときの処理...
      console.log('clipboard denied.');
    });
  }else if(window.clipboardData){
    //IE用の処理...
  }else if(document.execCommand){
    //非SSLサイトと古いブラウザ用の処理...
  }else{
    //クリップボードにアクセスできなかった場合の処理
    console.log('Can not copy. No permission and execCommand died.');
  }
}

//コピーするボタンのクリックイベントに上記の関数を登録
const btnCopy = document.getElementById('btn-copy');
btnCopy.addEventListener('click', function(){
  ag2copy();
});

document.getElementById(‘ID’) : 指定されたIDに一致する要素を表すElementオブジェクトを返す。無ければ「null」を返す。

要素.innerHTML : 指定した要素内のHTMLまたはXMLのマークアップを取得する。値を設定した場合は、要素のすべての子孫を削除して、htmlStringの文字列で与えられたHTMLを解析して構築されたノードに置き換える。

対象要素.addEventListener(‘イベントのタイプ’, ‘関数’, ‘イベント伝播順’) : 対象要素に指定のイベントでコールする関数を登録。第3引数(初期値 : false)でイベントの伝播する方向を指定できる。falseでDOM階層の下位から上位に伝播。

 

 

window.clipboardDataを使う方法

IEに対応する場合は、IE独自仕様のwindow.clipboardDataオブジェクトのメソッドを利用してクリップボードにコピーする。(IEでのみ利用できる。)

let targetEle = document.getElementById('txt-copy');

if(window.clipboardData){
  //クリップボードにコピーを実行
  let ieResult = window.clipboardData.setData("Text", targetEle.innerHTML);
  //結果をコンソールに表示
  console.log('setData : '+ieResult);
}

window.clipboardData.setData(フォーマット, データ) : 指定したフォーマットでのデータをクリップボードにセットする。フォーマットは、「”Text”」(テキスト形式のデータ)か「”URL”」(URL形式のデータ)を指定できる。成功した場合はtrueを返し、失敗した場合はfalseを返す。

 

 

execCommandメソッドを使う方法

execCommand()メソッドのmozillaの公式ドキュメント

 

Clipboard APIを利用できない非SSLサイトや古いブラウザなどに対応する場合は、documentオブジェクトが持つexecCommand()メソッドを使用する。

※ execCommand()メソッドは、既に公式に廃止されているメソッド。

※ 後方互換のため現状はまだほとんどのブラウザがサポートしているが、いつサポートされなくなってもおかしくないので、一時的な対応として運用する。

 

execCommand()メソッドの要約

  • execCommand()メソッドは、編集可能領域の内容にアクセスして引数に指定したコマンドを実行することができる。(フォームのテキスト編集可能な要素やcontenteditable属性がtrueになっている要素でのみ使用できる。)
  • DOM上で現在選択状態になっている範囲に対して、指定したコマンドが実行される。
  • 返値はBoolean。コマンドが対応していないか無効であればfalse、コマンドを実行できたらtrueを返す。
  • ユーザーの操作で発火したイベントで実行された場合にのみexecCommandメソッドはtrueを返して実行できる。(ユーザーの操作と関係無くsetTimeoutなどで実行させてもfalseが返り実行できない。)

※ 編集可能領域でないテキストのコピーもできたので、実際の実装状況は不明。

 

execCommand()メソッドでのコピーの実装

execCommand()メソッドの第1引数に「’copy’」を指定して実行することで、DOM上で現在選択状態になっている範囲がクリップボードにコピーされる。

※ execCommand()メソッドでコピーする場合は、コピーしたいテキストがDOM内で選択状態になっている必要がある。

 

コピー実行の手順

  1. コピーしたいテキストを内包しているHTML要素を取得。(DOM上に無い場合は動的に生成して挿入。)
  2. 取得した要素を、selectionオブジェクトを利用して選択状態にする。
  3. execCommand(‘copy’)を実行。
  4. 選択している範囲がクリップボードにコピーされる。

※ Webブラウザ上でwindowオブジェクトはグローバルオブジェクトなので、「window.getSelection()」の「window.」は省略できる。

※ documentオブジェクトも同じように動作するgetSelection()メソッドを持っているので、「document.getSelection()」で指定しても同じ。

let targetEle = document.getElementById('txt-copy');

if(document.execCommand){
  //コピーしたいテキストを選択状態にする
  getSelection().selectAllChildren(targetEle);
  //コピーを実行
  document.execCommand('copy');
  //選択状態を解除
  getSelection().removeAllRanges();
}

window.getSelection() : ユーザーの操作により選択状態になっている文字列やその範囲などの情報を保持するselectionオブジェクトを返す。

セレクション.selectAllChildren(‘親ノード’) : 指定したノードが内包するすべての子ノード(指定したノード自身は含まない。)をセレクションへ追加する。このとき直前のセレクションは失われる。

document.execCommand(実行するコマンド名, aShowDefaultUI, aValueArgument) : 第1引数で指定したコマンドを実行する。第2引数「aShowDefaultUI」は既定のユーザインターフェースを表示するかどうかをBooleanで指定。(対応状況はブラウザによる。) 第3引数「aValueArgument」は追加の引数を必要とするコマンド名を指定している場合の引数。引数が不要な場合はnulldを指定。

セレクション.removeAllRanges() : selectionオブジェクトのメソッド。セレクションから全てのレンジを削除、anchorNodeとfocusNodeのプロパティーを取り去ってnullにし、何も選択されていない状態にする。

 

 

この記事をシェア
この記事のURL

https://memo.ag2works.tokyo/post-2504/

コピー
この記事のタイトル

JavaScriptで任意のテキストをデバイスのクリップボードにコピーする方法。 | memo メモ [AG2WORKS]

コピー
この記事のリンクタグ

<a href="https://memo.ag2works.tokyo/post-2504/" target="_blank" rel="noopener">JavaScriptで任意のテキストをデバイスのクリップボードにコピーする方法。 | memo メモ [AG2WORKS]</a>

コピー
※ フィールドをクリックでコピーするテキストの編集ができます。

この記事へのコメント

コメントの書き込みはまだありません。

  • コメント内のタグはエスケープ処理され、文字列として出力されます。
  • セキュリティーのため、投稿者のIPアドレスは取得されます。
  • 管理者が内容を不適切と判断したコメントは削除されます。
  • このフォームにはスパム対策として、Googleの提供するreCAPTCHAシステムが導入されています。
    (Google Privacy Policy and Terms of Service.)