【javascript】ドラッグアンドドロップで画像をアップロードする方法メモ〜jqueryも使った

はじめに

以前につくったサービスの改修で必要になった。

どこかのブログに書いてあったのをコピーして動いたのでそれでよしとしていたのだが、今回はそれが1ページに複数必要になって問題が発生したので作り直してクラスにしてみた
DOM操作にjQuery使っているのでjQueryは読み込む必要あり

完成イメージ

初期画面
f:id:yoppy0066:20161014025718p:plain

ドラッグ&ドロップ後
f:id:yoppy0066:20161014030016p:plain

実装

作ったクラスを呼び出す

<script src="/path/to/jquery.min.js"></script>
<script src="/path/to/uploadImage.js"></script>

<div id="dropzone"><!-- ここにドラッグ&ドロップできるエリアが作られる --></div>
<script>
$(function() {
  var m = new UploadImage({
  target: "dropzone", // 追加するID指定
  contentUrl: "",     // 初期表示に画像を設定したい場合は設定
  uploadData: {       // $_POST["image_data"]で送信したい場合
    name:"image_data",
	value: ""
  },
  maxWidth: 320,     // アップロードできる画像サイズ設定
  maxHeight: 180
});
m.init();
});
</script>

今回つくったクラス
uploadImage.js

var UploadImage = UploadImage || {};

// コンストラクタ
UploadImage = function(params) {

    // このクラスでつくったDOMを挿入するIDを設定
    this.target = params.target;

    // 初期表示で画像を表示したい場合に設定
    this.contentUrl = params.contentUrl ? params.contentUrl : "";

    // アップロードする画像サイズを制限したい場合に設定
    this.maxWidth = params.maxWidth ? params.maxWidth : null;
    this.maxHeight = params.maxHeight ? params.maxHeight : null;

    // サーバに送信する画像データのパラメータ名を設定
    this.uploadData = params.uploadData;

    // 必要なDOM要素を定義
    this.dropzone = $('<div class="dropzone"></div>');
    this.message = $('<span>ここに画像をドラッグ&ドロップ</span>');
    this.image = $('<img style="width:auto; height:auto; max-width:100%; max-height:100%;" />');
    this.uploadDataElm = $('<input type="hidden" name="' + this.uploadData.name + '" value="' + this.uploadData.value  + '" />');
    this.input = $('<input type="file" accept="image/*" />');
};

// メソッド定義
UploadImage.prototype = {
	
    init: function()
    {
        this.setEventHandler();
        this.draw();
    },

    setEventHandler: function()
    {
        var self = this;
        this.dropzone.on("dragover", function(e) {
            e.stopPropagation();
            e.preventDefault();
            e.originalEvent.dataTransfer.dropEffect = 'copy';
        });
		
        this.dropzone.on("drop", function(e) {
            e.stopPropagation();
            e.preventDefault();
            var files = e.originalEvent.dataTransfer.files;
            var file = files[0];
            var reader = new FileReader();

            if (file.type != "image/png" && file.type != "image/jpeg" && file.type != "image/gif") {
                alert("画像ファイルを選択してください");
            } else {
                reader.readAsDataURL(file);
                reader.onload = function() {
                    self.readImage(reader, file.name);
                }
            }
        });

        this.input.on("change", function(e) {
            var file = e.target.files;
            var reader = new FileReader();
            reader.readAsDataURL(file[0]);
            reader.onload = function(){
                self.readImage(reader, file[0].name);
           }
        });
    },

    readImage: function(reader, name)
    {
        var self = this;
        this.checkSize(reader, function() {
            self.image.attr("src", reader.result);
            self.uploadDataElm.val(reader.result);
        }, function() {
            alert("画像サイズが大きすぎます");
        });
    },

    checkSize: function(reader, cb, cb_error)
    {
        var self = this;
        var image = $("<img />");
        image.attr("src", reader.result);
        image.on("load", function() {
            if (self.maxWidth && self.maxWidth < this.naturalWidth)
                cb_error();
            else if (self.maxHeight && self.maxHeight < this.naturalHeight)
               cb_error();
            else
               cb();
        });
    },

    draw: function()
    {
        if (this.uploadData.value)
            this.image.attr("src",this.uploadData.value);
        else if (this.contentUrl)
            this.image.attr("src",this.contentUrl);

        this.dropzone.empty();
        this.dropzone.append(this.message);
        this.dropzone.append(this.image);
        this.dropzone.append(this.uploadDataElm);

        $("#" + this.target).append(this.dropzone);
        $("#" + this.target).append(this.input);
    }
};

mp4の場合、サーバ側(PHP)

// これで取得可能
$data = $_POST["image_data"];

// バイナリデータで送信しているので
$data = str_replace("data:image/jpeg;base64,", "", $data);
$data = str_replace(" ", "+", $data);
$data = base64_decode($data);

// ファイルをサーバに保存
file_put_contents($data, "ファイル名");

クラス化するとこういうとき便利ですね
以上です