カテゴリー
コンピューター

Vue.js 3 でラップしてコンポーネント化した Dropzone.js にちょっとしたカスタマイズをいくつか加えた

やりたいこと

  • Dropzone.js エリアの文言を変更したい。
  • ファイルアップロード成功後は Dropzone.js エリアのサムネイルを自動的に消したい。
  • アップロードエラー時のメッセージを変更したい。
  • ファイルアップロード失敗後は Dropzone.js エリアのボタンクリックでサムネイルを消したい。

Dropzone.js エリアの文言を変更したい。

公式ページ 通りに、設定時に dictDefaultMessage を指定すれば実現できました。

$ git diff
diff --git a/laravel/resources/js/components/BaseDropzone.vue b/laravel/resources/js/components/BaseDropzone.vue
index 69c5313..d540544 100644
--- a/laravel/resources/js/components/BaseDropzone.vue
+++ b/laravel/resources/js/components/BaseDropzone.vue
@@ -19,9 +19,16 @@ export default {
     const initDropzone = () => {
       Dropzone.autoDiscover = false;
       //new Dropzone("div#myId", { url: "https://httpbin.org/post" });
-      const myDropzone = new Dropzone("div#myDropzoneId", { url: props.url });
+      const myDropzone = new Dropzone("div#myDropzoneId", {
+        url: props.url,
+        dictDefaultMessage:
+          "画像ファイルをここにドロップするか、クリックしてアップロード",
+      });
       myDropzone.on("success", (file, response) => {
         emit("onSuccess", file, response);
       });
$

ファイルアップロード成功後は Dropzone.js エリアのサムネイルを自動的に消したい。

次の順番で取り組みました。

  1. サムネイルの見た目のみを消す。
  2. DOM からサムネイルを消す。

サムネイルの見た目のみを消す。

次のコードで、 dz-success を class に含むタグを徐々に見えなくすることができました。

<style>
.dz-success {
  transition: opacity 10s, visibility 0s ease 10s;
  opacity: 0;
  visibility: hidden;
}
</style>

DOM からサムネイルを消す。

たまたま Tips – Dropzone.js を見つけて、これで行けそう! と思いました。つまり、 Dropzone.js のアップロードが終わったあたりのイベントで、さらにプレビューをクリックしたときのイベントを定義し、そこで removeFile を呼び出すようにすればよいです。

To access the preview html of a file, you can access file.previewElement. For example:

myDropzone.on("addedfile", function(file) {
  file.previewElement.addEventListener("click", function() {
    myDropzone.removeFile(file);
  });
});

公式ドキュメントを読んで、もっと理解した方がよい部分を見つけられました。 Dropzone methods – Dropzone.js によると、 .removeFile(file) そのイベントで扱っているファイルを削除できるようです。これを、サムネイルをフェードアウトした後に呼び出せば良さそうです。

やってみたところ、次のコードで実現できました♪ setTimeout のコールバックで myDropzone.removeFile(file) を直接呼び出さずに、これを実行するだけの関数を呼び出すようにしたところがポイントです。そうしなければ setTimeout で指定した時間停止することなく、 myDropzone.removeFile(file) が実行されてしまいますので。

      myDropzone.on("success", (file, response) => {
        emit("onSuccess", file, response);
        setTimeout(() => myDropzone.removeFile(file), 10000);
      });

アップロードエラー時のメッセージを変更したい。

  1. JSON エラーレスポンスの場合は error プロパティがあれば自動でそれを使うようです。 → How to show an error returned by the server? – FAQ · Wiki · Matias Meno / Dropzone · GitLab
  2. エラー時のイベントで何かできそうです。 → error – Dropzone.js
  3. 答えがいきなり見つかりました! でも jQuery です。。。 → dropzone.js – How to display error message of jquery dropzone – Stack Overflow
  4. jQuery を使わないようにするためには、次のページを参考にすれば良さそうです!↓

調査、学習は上の順番で進んでいき、次のコードで実現できました♪

      myDropzone.on("error", function (file, errorMessage) {
        console.log("error", file, errorMessage); // TODO デバッグ用途。後で消すこと。
        // レスポンスの内容を使用するときは、エラーメッセージの後ろに付与すればよさそう。
        file.previewTemplate.getElementsByClassName(
          "dz-error-message"
        )[0].textContent = "アップロードに失敗しました。";
      });

ファイルアップロード失敗後は Dropzone.js エリアのボタンクリックでサムネイルを消したい。

  1. インスタンス化する際にこれを true にすれば行ける? → Configuration options addRemoveLinks – Dropzone.js
  2. デフォルトの文字列、 "Remove file" を変更したい。 → Configuration options dictRemoveFile – Dropzone.js
  3. addRemoveLinks を true にしたことにより他のリンクも追加されたため、それの文言も変更 →

今回は、設定するだけで実現できました。次のコードです。

      const myDropzone = new Dropzone("div#myDropzoneId", {
        url: props.url,
        addRemoveLinks: true,
        dictDefaultMessage:
          "画像ファイルをここにドロップするか、クリックしてアップロード",
        dictCancelUpload: "アップロードをキャンセル",
        dictRemoveFile: "操作エリアから除去",
      });

完成

今回修正したコードの全体です。

<template>
  <div id="myDropzoneId" class="dropzone"></div>
</template>

<script>
import { onMounted } from "vue";
import Dropzone from "dropzone";
export default {
  name: "BaseDropzone",
  props: {
    url: {
      type: String,
      require: true,
      default: "",
    },
  },
  emits: ["onSuccess"],
  setup(props, { emit }) {
    const initDropzone = () => {
      Dropzone.autoDiscover = false;
      //new Dropzone("div#myId", { url: "https://httpbin.org/post" });
      const myDropzone = new Dropzone("div#myDropzoneId", {
        url: props.url,
        addRemoveLinks: true,
        dictDefaultMessage:
          "画像ファイルをここにドロップするか、クリックしてアップロード",
        dictCancelUpload: "アップロードをキャンセル",
        dictRemoveFile: "操作エリアから除去",
      });
      myDropzone.on("success", (file, response) => {
        emit("onSuccess", file, response);
        setTimeout(() => myDropzone.removeFile(file), 10000);
      });
      myDropzone.on("error", function (file, errorMessage) {
        console.log("error", file, errorMessage); // TODO デバッグ用途。後で消すこと。
        // レスポンスの内容を使用するときは、エラーメッセージの後ろに付与すればよさそう。
        file.previewTemplate.getElementsByClassName(
          "dz-error-message"
        )[0].textContent = "アップロードに失敗しました。";
      });
    };

    onMounted(() => {
      initDropzone();
    });
  },
};
</script>

<style>
.dz-success {
  transition: opacity 10s, visibility 0s ease 10s;
  opacity: 0;
  visibility: hidden;
}
</style>

続いて、今回実現するために手を加えた部分のみ、つまり差分です。

$ git diff
diff --git a/laravel/resources/js/components/BaseDropzone.vue b/laravel/resources/js/components/BaseDropzone.vue
index 69c5313..fac1a98 100644
--- a/laravel/resources/js/components/BaseDropzone.vue
+++ b/laravel/resources/js/components/BaseDropzone.vue
@@ -19,9 +19,24 @@ export default {
     const initDropzone = () => {
       Dropzone.autoDiscover = false;
       //new Dropzone("div#myId", { url: "https://httpbin.org/post" });
-      const myDropzone = new Dropzone("div#myDropzoneId", { url: props.url });
+      const myDropzone = new Dropzone("div#myDropzoneId", {
+        url: props.url,
+        addRemoveLinks: true,
+        dictDefaultMessage:
+          "画像ファイルをここにドロップするか、クリックしてアップロード",
+        dictCancelUpload: "アップロードをキャンセル",
+        dictRemoveFile: "操作エリアから除去",
+      });
       myDropzone.on("success", (file, response) => {
         emit("onSuccess", file, response);
+        setTimeout(() => myDropzone.removeFile(file), 10000);
+      });
+      myDropzone.on("error", function (file, errorMessage) {
+        console.log("error", file, errorMessage); // TODO デバッグ用途。後で消すこと。
+        // レスポンスの内容を使用するときは、エラーメッセージの後ろに付与すればよさそう。
+        file.previewTemplate.getElementsByClassName(
+          "dz-error-message"
+        )[0].textContent = "アップロードに失敗しました。";
       });
     };

@@ -32,6 +47,13 @@ export default {
 };
 </script>

+<style>
+.dz-success {
+  transition: opacity 10s, visibility 0s ease 10s;
+  opacity: 0;
+  visibility: hidden;
+}
+</style>
 <!--
 ここでスタイルを読み込むことも可能
 <style src="../../../node_modules/dropzone/dist/dropzone.css"></style>
$

おわりに

終わってから振り返ってみると、アップロード成功後に自動的にサムネイルを消すのは必要なかったのではないかとも思えました。 その場合は、 success 時のイベントの変更と、スタイルを取り除けばよいです。

Dropzone.js でやりたかったカスタマイズは、これでおしまいです。長かったですが、満足できました。

以上です。

コメントを残す