JavaScriptで実装したクリップボードへのコピー機能が動かなかった
はじめまして、PRESSでエンジニアとしてお手伝いをさせて貰っているyamane (id:yusukeyamane01)です Twitterもやっています。
JavaScriptで実装したクリップボードへ文字列をコピーする機能を修正した時の事を記事にしたいと思います。
コードが動かなかった理由
結論を先に言うと、CSSの指定が問題で処理が正しく実行できていませんでした。
修正する前はHTMLが以下のようになっていて
button.editor-btn{ onclick: "handleURLCopy();" } | プロフィールページのURLをコピー p#urlField style="visibility:hidden;position:absolute;" = current_url
JavaScriptが以下のようになっていました
handleURLCopy() { const target = document.getElementById('#urlField'); const range = document.createRange(); range.selectNodeContents(target); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); document.execCommand('copy'); window.getSelection().removeAllRanges(); this.hideMenuModal() this.$notice.success('コピーしました'); }
上記のコードでは、HTMLのPタグ内にコピーしたいURLを持たせJavaScriptでPタグ内の文字列を選択状態にして、document.execCommand('copy');
でクリップボードへコピーしていました。
問題の原因となっていたのはHTMLにある以下の記述でした。
style="visibility: hidden;position:absolute;"
この記述はコピーしたい文字列をviewに表示させない為に記述していたのですが、visibility: hidden;
としてしまうと、対象の要素を選択状態にすることが出来ずに処理が正常に行われていませんでした。
どのように問題を解決したか
動かない原因が対象の文字列を選択出来なくしていたことだと判明したので、解決方法は次の二択だと考えました。
- visibility:hiddenではなく、opacity: 0;で文字列を隠蔽する
- HTMLにコピー対象を書き込むのでは無く、コピー対象の生成までをJavaScriptで処理する
今回は後者を選択しました。後者の方がより汎用性高く使い回せる関数になると考えたからです。修正後のコードは以下です。
button.editor-btn{ onclick: "handleURLCopy();" } | プロフィールページのURLをコピー
function handleURLCopy() { copyURLToClipboard(location.href) this.hideMenuModal() this.$notice.success('コピーしました'); } function copyURLToClipboard(string) { if (!document.queryCommandSupported('copy')) return new Error('このブラウザはクリップボードへのコピーに対応していません'); if (typeof string !== 'string') return new TypeError(`except string but got ${typeof string}`); // 仮想のdiv要素を作りそこに引数で受けた文字列を持たせる var tempElement = document.createElement('div'); tempElement.appendChild(document.createElement('pre')).textContent = string; // 仮想のdiv要素をviewに表示させないようにする tempElement.style.position = 'fixed'; tempElement.style.left = '-100%'; document.body.appendChild(tempElement); document.getSelection().selectAllChildren(tempElement); document.execCommand('copy'); document.body.removeChild(tempElement); }
これでクリップボードへのコピー関数は正常に動くようになりました。この記事が、同じような問題で困っている人の手助けになれば幸いです。