Stimulusでドラッグ&ドロップ時に画像のアップロードを行う
はてなフォトっぽいやつを実装してみます。
やり方
view
formのinput file は非表示にしておきます(d-noneスタイル)。
Stimulusのcontrollerは file-drop-controller
というものを用意し、ドラッグ&ドロップの操作はここで行うようにします。
click時の操作は元々用意していた preview-controller
にて実施します。
# haml .uploading-image.pt-3 = form_with url: user_images_path(@user), local: true, data: { controller: "preview file-drop" } do |f| .input-group.d-none = f.file_field :images, class: "form-control override-bs-file image-selection", data: {"action": "input->preview#show", "file-drop-target": "file", "preview-target": "file" } .drag-and-drop-image.mt-2 .drag-and-drop-image-message{"data-action": "click->preview#selectImage dragover->file-drop#dragover dragleave->file-drop#dragleave drop->file-drop#drop drop->preview#show"} クリックしてファイルを選択するか、ここにファイルをドラッグしてください
Stimulus
簡単なclick時の操作から。
上記のようにviewとしては、Stimulusで扱えるようにinput fileにtargetを追加し、clickイベント発生時に selectImage
actionを呼ぶようにしておきます。
Stimulusでは click()
を実行するだけ。
export default class extends Controller { static targets = ["content", "modal", "file"] selectImage() { this.fileTarget.click() } }
続いてドラッグ&ドロップ。
こちらもviewでdragover, dragleave, dropイベントを用意します。
(drop後にはmodalでpreview表示するために、preview#show も実行するようにしています。)
Stimulusではcssで背景を変更するためのstyleの追加・削除を行い、drop時にinput fileへの設定を行なっているだけです。
// app/javascript/controllers/file_drop_controller.js import { Controller } from '@hotwired/stimulus' export default class extends Controller { static targets = ["file"] dragover(e) { e.preventDefault() e.target.classList.add("dragging") } dragleave(e) { e.preventDefault() e.target.classList.remove("dragging") } drop(e) { e.preventDefault() e.target.classList.remove("dragging") const files = e.dataTransfer.files if (typeof files[0] !== 'undefined') { this.fileTarget.files = files } } }
//scss // uploading image .drag-and-drop-image { border: 2px dashed silver; cursor: pointer; font-size: 1.2em; text-align: center; .drag-and-drop-image-message.dragging { background-color: rgb(233, 233, 233); } }
感想
まぁ、Stimlus難しくはないんですよね。単純なやつならいいかなという気はするのですが、もう少しcontrollerとactionが増えてくると辛みがありそうな気がします。
See Also
・cropper.jsを使ってActiveStorageで画像アップロード時に切り抜きを行う
プレビューの実装はこちら