そろそろ決定版が欲しいな。
前置き
今までは
と既存のものを選択してコピーするか、無いものをコピーしたいときは
とコピーしたいDOMを作ってそれを選択するというまどろっこしい方法を取っていた。
Qiitaにも色々記事はある。
でもこれらの方法は主にRangeの処理がとてもとても面倒なので、最近は使っていない。
目新しい内容ではないが、使用頻度が高いのでまとめる。
要件
- 任意のJS側で用意した文字列をクリップボードに保存させる。
- 動作のトリガーは主にボタンクリックのイベント駆動
- 通常のコピー動作を阻害しない
- 複数のコピー処理を追加したときに互いに干渉しない
- 後処理が楽であって欲しい
コード
// 登録したい要素
const element = document.createElement('hoge'); // document.querySelector('hoge')
element.addEventListener('click', (e) => {
document.addEventListener('copy', (e) => {
e.preventDefault();
e.clipboardData.setData('text/plain', 'コピーしたい文字列');
}, {once:true});
document.execCommand('copy');
});
これだけ。
何かのイベントを契機にcopyイベントを登録して、document.execCommand('copy');
で即座に手動実行。
clipboardData.setData()
で選択中文字列ではなく色々手動で設定できる。
もちろんコールバック中にDOM操作ができるので、欲しい文字列はDOM中から自由に取ってきて加工できる。
イベントにonce
オプションをつけることで、実行後にイベント登録は解除される。
よってコピー後も通常のコピーが出来るし、別のcopyイベントも登録できるし、当然再度同じイベントを登録することもできる。
後腐れなし、と思っている。
(オマケ)Bootstrapなどがあるときの視覚的補助
自分で作っているならば動作に不安は無いが、知らぬ人にはコピーが起きても変化が無いので味気ない。
// ツールチップの遅延非表示。クリックで表示を前提にしている(delayオプションが効かないのでやむなく)
const hideTooltipDelay = (element, dilay) => {
setTimeout(() => {
// ツールチップはBootstrap(jQuery)の機能なので、Qiitaが読み込んでいるものを使う
$(element).tooltip('hide');
}, dilay);
}
// クリックすることで指定のstringをクリップボードにコピーするElementを返す関数
const createCopyButton = (string, tag = 'span') => {
if (typeof string == 'function') {
string = string();
}
const element = document.createElement(tag);
element.addEventListener('click', (e) => {
document.addEventListener('copy', (e) => {
e.preventDefault();
e.clipboardData.setData('text/plain', string);
}, {once:true,});
document.execCommand('copy');
hideTooltipDelay(e.target, 1000)
});
element.dataset.toggle = 'tooltip';
element.dataset.originalTitle = 'Copied';
element.dataset.trigger = 'click';
return element;
}
褒められたコードではないのだが、ツールチップでcopyされたことを目視することができる。
が、本当に処理周りの理解が追いついてなくて、消し方や2回めのクリック時にtooltipが出ない問題を抱えている。(manual triggerで作ったほうがよかったかな)