1. ホーム
  2. javascript

[解決済み] iOSでJavascriptを使用してクリップボードにコピーする

2023-04-30 17:30:06

質問

URLをクリップボードにコピーするために、この関数を使っています。

function CopyUrl($this){

  var querySelector = $this.next().attr("id");
  var emailLink = document.querySelector("#"+querySelector);

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

  try {  
    // Now that we've selected the anchor text, execute the copy command  
    var successful = document.execCommand('copy', false, null);
    var msg = successful ? 'successful' : 'unsuccessful'; 

    if(true){
        $this.addClass("copied").html("Copied");
    }

  } catch(err) {  
    console.log('Oops, unable to copy');  
  }  

  // Remove the selections - NOTE: Should use   
  // removeRange(range) when it is supported  
  window.getSelection().removeAllRanges();
}

デスクトップのブラウザではすべてうまくいきますが、iOSデバイスではうまくいきません。私の関数は正常に戻りますが、データがクリップボードにまったくコピーされません。何が原因で、どうすればこの問題を解決できるのでしょうか?

どのように解決するのでしょうか。

アップデート! iOS >= 10

iOS (>= 10) の Safari で、選択範囲とちょっとしたハックによって、クリップボードに直接コピーすることができるようです。iPhone 5C iOS 10.3.3 と iPhone 8 iOS 11.1 で試してみました。ただし、いくつかの制約があるようです。

  1. テキストは、以下の場所からしかコピーできません。 <input><textarea> 要素で構成されます。
  2. テキストを保持する要素が ではなく の中にある場合 <form> の中にあるのであれば、それは contenteditable .
  3. テキストを保持する要素は、必ず ではなく である readonly になることはありません (試すことはできますが、これはどこにも文書化されていない正式な方法です)。
  4. 要素内のテキストは選択範囲内でなければなりません。

これら4つの"要件"をすべてカバーするには、以下のようになります。

  1. コピーするテキストを <input> または <textarea> 要素を使用することができます。
  2. の古い値を保存します。 contenteditablereadonly をコピーした後、それらを復元できるようにするためです。
  3. 変更 contenteditabletrue であり readonly から false .
  4. を作成します。 の範囲 を使用して目的の要素を選択し、ウィンドウの選択範囲に追加します。
  5. を設定します。 の選択範囲 を要素全体に対して設定します。
  6. 以前の contenteditablereadonly の値を指定します。
  7. 実行する execCommand('copy') .

これにより、ユーザーのデバイスのキャレットが移動し、目的の要素のすべてのテキストを選択し、自動的にコピーコマンドを発行します。ユーザーは、テキストが選択されていることを確認し、選択/コピー/貼り付けのオプションを持つツールチップが表示されます。

さて、これは少し複雑で、単にコピー コマンドを発行するには手間がかかりすぎるように見えるので、これが Apple が意図したデザイン選択であったかどうかは分かりませんが、誰にも分かりません... その間に、この は iOS >= 10 で動作しています。 .

このため この のようなポリフィルを使えば、このアクションを簡略化し、クロスブラウザに対応させることができます (ありがとうございます。 トスカン に感謝します)。

動作例

まとめると、必要なコードは以下のようになります。

function iosCopyToClipboard(el) {
    var oldContentEditable = el.contentEditable,
        oldReadOnly = el.readOnly,
        range = document.createRange();

    el.contentEditable = true;
    el.readOnly = false;
    range.selectNodeContents(el);

    var s = window.getSelection();
    s.removeAllRanges();
    s.addRange(range);

    el.setSelectionRange(0, 999999); // A big number, to cover anything that could be inside the element.

    el.contentEditable = oldContentEditable;
    el.readOnly = oldReadOnly;

    document.execCommand('copy');
}

なお el この関数のパラメータは <input> または <textarea> .

古い答え:以前の iOS バージョン

以下のように iOS 10 には、Safari のためにいくつかの制限 (これは実際にはセキュリティ対策です) があります。 クリップボードAPI :

  • 発火する copy イベントを発生させ、有効な選択範囲と cutpaste は、フォーカスされた編集可能なフィールドでのみ使用されます。
  • ショートカットキーによる OS のクリップボードの読み書きをサポートするだけであり document.execCommand() . ショートカット キーとは、クリック可能なキー (例: コピー/貼り付けのアクション メニュー、iOS のカスタム キーボード ショートカット) または物理キー (例: 接続された bluetooth キーボード) を意味することに留意してください。
  • をサポートしません。 ClipboardEvent コンストラクタをサポートしていません。

ということで、(少なくとも今の時点では) iOS デバイスで Javascript を使ってクリップボードのテキスト/値をプログラム的にコピーすることはできません。 . 何かをコピーするかどうかを決定できるのは、ユーザーだけです。

しかし、プログラム的に何かを選択することは可能です。 そのため、ユーザーは選択部分に表示される "コピー" ツールチップを押すだけでよいのです。これは上記と全く同じコードで実現でき、単に execCommand('copy') を削除するだけで、上記と全く同じコードで実現できます。これは確かにうまくいきません。