表示されたテキストをボタンクリック一つでクリップボードにコピーしてくれる機能、あったら便利ですよね。
ということで、今どきのWebサービスでよく見かける以下のようなボタンを実装してみました。
今回の実装で用いたJSライブラリはStimulus。
Rails7でStimulus使って実装してきたいよー、という方の参考になれば幸いです。
開発環境
- Ruby 3.1.2
- Ruby on Rails 7.0.3
- Bootstrap 5.1.3
- jsbundling-rails (1.0.3)
- cssbundling-rails (1.1.1)
- M1 Macbook Air 2020
- mac OS Monterey (ver. 12.4)
- ターミナル bash (Rosetta 2 使用)
JS + Stimulusでクリップボードにコピーする方法
それでは順番に解説していきます。
フォームを作成する
まずは、テキストを表示させるためのフォームとコピーイベント発火用のボタン(以下コピーフィールド)を作成します。
CSS、およびアイコンはbootstrap5を使用しています。
<h2 class="mb-3">クリップボード↓</h2>
<div class="mb-3">
URL: <input type="text" value="kobacchi.com" readonly>
<a href="#" class="btn btn-secondary"><i class="bi bi-clipboard"></i> Copy to Clipboard</a>
</div>
Stimulusコントローラーを作成
以下のコマンドでStimulusコントローラーを作成します。
$ rails g stimulus コントローラー名
例)
$ rails g stimulus clipboard
上記のコマンドで、app/javascript/controllers
ディレクトリ以下にclipboard_controller.js
ファイルが追加されているかと思います。
HTMLにdata属性を設定する
Stimulusコントローラー(target、action)とHTMLファイルを接続するために、コピーフィールドにdata属性
を追加します。
追加するdata属性の種類は以下の3つです。
- data-controller
- data-action
- data-{controller}-target
Stimulusのdata属性
の役割について詳しく知りたい方は公式マニュアルをご覧ください。
<h2 class="mb-3">クリップボード↓</h2>
<div data-controller="clipboard">
<div class="mb-3">
URL: <input data-clipboard-target="source" type="text" value="kobacchi.com" readonly>
<a href="#" class="btn btn-secondary"
data-clipboard-target="copy_button"
data-action="clipboard#copy">
<i class="bi bi-clipboard"></i> Copy to Clipboard
</a>
</div>
</div>
これで、Stimulusを動かす準備が整いました。
Stimulusコントローラーにターゲット、アクションを追加する
Stimulusコントローラーに要素のターゲットsource
, copy_button
、およびボタン(リンク)クリック時にテキストをクリップボードにコピーするためのアクションcopy()
を追加します。
export default class extends Controller {
static targets = [ "source", "copy_button" ]
copy(){
// ↓ボタンクリック時にテキスト(this.sourceTarget.value)をクリップボードにコピーする
navigator.clipboard.writeText(this.sourceTarget.value)
// ↓コピー完了後にボタン(リンク)のテキストを上書きする
this.copy_buttonTarget.innerHTML = '<i class="bi bi-clipboard-check"></i> Copied!!'
}
}
これで完成です。
以下のような動作になればOKです。
複数のコピーフィールドを設置する場合
以下のように、複数のコピーフィールドを設置する場合についてみていきましょう。
先ほど作成したStimulusのcopy()
アクションは再利用できるので、複数のコピーフィールドを設置する場合はコピーフィールド毎に新しいアクション(copy2(), copy3()など)を定義する必要はありません。
HTMLのコピーフィールドもvalueなどのテキスト以外はそのまま再利用できます。
上のような3つのコピーフィールドを設置する場合、HTMLは以下のようになります↓
<h2 class="mb-3">クリップボード↓</h2>
<!-- フィールド① -->
<div data-controller="clipboard">
<div class="mb-3">
URL: <input data-clipboard-target="source" type="text" value="kobacchi.com" readonly>
<a href="#" class="btn btn-secondary"
data-clipboard-target="copy_button"
data-action="clipboard#copy">
<i class="bi bi-clipboard"></i> Copy to Clipboard
</a>
</div>
</div>
<!-- フィールド② -->
<div data-controller="clipboard">
<div class="mb-3">
Blog: <input data-clipboard-target="source" type="text" value="こばっちブログ" readonly>
<a href="#" class="btn btn-secondary"
data-clipboard-target="copy_button"
data-action="clipboard#copy">
<i class="bi bi-clipboard"></i> Copy to Clipboard
</a>
</div>
</div>
<!-- フィールド③ -->
<div data-controller="clipboard">
<div class="mb-3">
PIN: <input data-clipboard-target="source" type="text" value="1234" readonly>
<a href="#" class="btn btn-secondary"
data-clipboard-target="copy_button"
data-action="clipboard#copy">
<i class="bi bi-clipboard"></i> Copy to Clipboard
</a>
</div>
</div>
各コピーフィールド毎にdata-controller属性
を指定するのを忘れずに。
続いては、Stimulusコントローラーのcopy()アクションですが、copy()の引数にeventを渡してevent.preventDefault()を付け加えるだけでOKです。
export default class extends Controller {
static targets = [ "source", "copy_button" ]
copy(event){
event.preventDefault() // ←追加する
navigator.clipboard.writeText(this.sourceTarget.value)
this.copy_buttonTarget.innerHTML = '<i class="bi bi-clipboard-check"></i> Copied!!'
}
}
これで、複数のコピーフィールドの設置が可能になりました。
参考資料
- STIMULUS Handbook
コメント