LoginSignup
13
11

More than 3 years have passed since last update.

JavaScriptでクリップボードへコピーをする方法

Last updated at Posted at 2019-11-06
  • 動作確認したブラウザ
    • Windows10 Pro 64bit
      • GoogleC hrome 78.0
      • Fire Fox 70.0
      • Microsoft Edge 44.18362
      • Internet Explorer バージョン11.418
    • MacOS Mojave 10.14.6
      • Google Chrome 78.0
      • Fire Fox 70.0
      • Safari 13.0

やりたいこと

[クリップボードへコピーする]ボタンをクリックすると画面に表示されている「コピー内容」がクリップボートに設定(コピー)されるようにしたい。

[コピー]ボタンでクリップボードへコピーする方法

後続に記載した[失敗したこと]で[(解決)...]となっているところには他の方法も記載しています。

copyUseJavaScript.js
function onClickCopy() {
    // コピー対象のpタグオブジェクトを取得する.
    let pTag = document.getElementById('copyTarget');
    // コピー内容を選択する.
    let range = document.createRange();
    range.selectNodeContents(pTag);
    let selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
    // 選択したものをコピーする.
    document.execCommand('copy');
    // コピー内容の選択を解除する.
    selection.removeAllRanges();
}
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" charset="utf-8">
    <script src="https://code.jquery.com/jquery-1.11.0.min.js" integrity="sha256-spTpc4lvj4dOkKjrGokIrHkJgNA0xMS98Pw9N7ir9oI=" crossorigin="anonymous"></script>
    <script src="copyUseJavaScript.js"></script>
</head>
<body>
    <div id="area">
        <p id="copyTarget">コピー内容</p>
        <input type="button" id="copy" value="クリップボードへコピーする" onclick="onClickCopy();">
    </div>
</body>
</html>

失敗したこと

コピーイベントを捕まえてClipboardAPIを利用したら、どこでコピーしても処理が動いてしまった。

ボタンのクリック処理でコピーイベントを発生させて、そのイベントを捕まえてClipboard APIを利用してクリップボードへコピーしたい内容を設定した。結果、画面のどこかでコピーをすればボタンをクリックしなくても処理は動いてしまう。もう決まった文字以外がコピーできない状態に・・・・。

a.gif

$(window).on('load', function () {
    document.addEventListener('copy', function(e) {
        // コピー内容を取得する.
        let copyTarget = $('#copyTarget').text();
        // クリップボートにコピー内容を設定する.
        e.clipboardData.setData('text/plain' , copyTarget);
        // もともとのコピーイベントを中止する.
        e.preventDefault();
    });
});

function onClickCopy() {
    if(window.clipboardData){
        // IEの場合の処理.
        let copyTarget = $('#copyTarget').text();
        window.clipboardData.setData('Text' , copyTarget);
    } else {
        // IE以外の場合の処理.
        // コピーイベントを発生させる.
        document.execCommand('copy');
    }
}

(解決)ボタンクリックイベントでコピーイベントの処理を1回分だけ登録したらコピーできた。

コメントで @lhankor_mhy さんから教えていただいた方法です。onceオプションが決め手です。
Safariではコピーができませんでした。理由がよく判らなくてモヤ:cloud_lightning:つきます。
※. 動作確認はMacのブラウザでしかしていません。
a.gif

function onClickCopy() {
    // ...省略...
        // IE以外の場合の処理.
        // コピーイベントでの処理を登録する(1回のみ).
        copyOverrideOnce(copyTarget);
        // コピーイベントを発生させる.
        document.execCommand('copy');
    }
}

function copyOverrideOnce(s) {
    document.addEventListener('copy', function(e) {
        e.clipboardData.setData('text/plain', s);
        e.preventDefault();
    },
    {once:true}
    );
}

<p>を選択状態にできなくてコピーできなかった。

document.execCommand('copy'); は選択されているものをコピーするので、コピー内容を選択できないとコピーできません。
最初は、pタグは選択できないことに気が付かず・・・jQueryを使わないでオブジェクトを取得したところエラーになって気が付きました。
a.gif

function onClickCopy() {
    // let pTag = $('#copyTarget');
    let pTag = document.getElementById('copyTarget');
    pTag.focus();
    // ★★コピー内容を選択する...ことはpタグなのでできない★★
    pTag.select();

    // 選択したものをコピーする.
    document.execCommand('copy');
}

(解決)<p>を選択状態にしてコピーでた。

上記のサイト様を参考に(ほぼコピペ)したら<p>を選択状態にしてコピーできました:ok_hand:
コードは一番上に記載しているものです。

(解決)<p>の内容を一時エリア(input)に設定して、そこを選択するようにしてコピーした。

以下の順番で処理してコピーしてみました。
1. <p>の値を取得する
2. コピー内容を一時的に格納するinputオブジェクトを作成する
3. inputオブジェクトをbodyの最後に追加する
4. inputオブジェクトの内容を選択する
5. 選択したものをコピーする

  • 欠点:画面が狭い場合、動的にオブジェクトを配置するため画面が一瞬揺れる

コピー内容を設定する一時エリアを非表示にしたらコピーできなかった。

もしかしたら、「コピーできない」というより「選択できない(copyInput.select();ができない)」のかもしれません。
document.execCommand('copy'); は選択されているものをコピーするので選択できないからコピーできないだけかもしれません。

function onClickCopy() {
    // コピー内容を一時的に格納するinputオブジェクトを作成する.
    let copyInput = $('<input type="text">');
    // ★★表示しないとコピーされない★★
    copyInput.css('display', 'none');
    copyInput.val(copyTarget);

    // inputオブジェクトをbodyの最後に追加する.
    $('body').append(copyInput);

    // inputオブジェクトの内容を選択する.
    copyInput.focus();
    copyInput.select();

    // 選択したものをコピーする.
    document.execCommand('copy');

    // inputオブジェクトを削除する.
    copyInput.remove();
}

コピー内容を一時的に格納するinputオブジェクトが見えてしまった。

一瞬だけど見えてしまった・・・inputだけでは調整しづらいです。

a.gif

function onClickCopy() {
    // コピー内容を一時的に格納するinputオブジェクトを作成する.
    let copyInput = $('<input type="text">');
    // ★★CSSをうまく設定しないと見えてしまいます★★
    copyInput.css({'position':'absolute','right':'0'});
    copyInput.val(copyTarget);

    // inputオブジェクトをbodyの最後に追加する.
    $('body').append(copyInput);

    // inputオブジェクトの内容を選択する.
    copyInput.focus();
    copyInput.select();

    // 選択したものをコピーする.
    document.execCommand('copy');

    // inputオブジェクトを削除する.
    copyInput.remove();
}

(解決)コピー内容を一時的に格納するinputオブジェクトをdivオブジェクトで囲ってスタイルを設定して見えないようにした。

function onClickCopy() {
    // コピー内容を一時的に格納するinputオブジェクトを作成する.
    let copyInput = $('<input type="text">');
    copyInput.css({'position':'absolute','right':'0'});
    copyInput.val(copyTarget);

    // inputオブジェクトを子要素に持つdivオブジェクトを作成する.
    let copyArea = $('<div>');
    copyArea.css({'position':'absolute','left':'0'});
    copyArea.append(copyInput);

    // divオブジェクトをbodyの最後に追加する.
    $('body').append(copyArea);

    // inputオブジェクトの内容を選択する.
    copyInput.focus();
    copyInput.select();

    // 選択したものをコピーする.
    document.execCommand('copy');

    // divオブジェクトを削除する.
    copyArea.remove();
}
13
11
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11