読者です 読者をやめる 読者になる 読者になる

【JavaScript】ドラッグ&ドロップで画像を非同期アップロードできるライブラリ dropzone.js の デフォルトCSS を有効にしたままカスタマイズする

【追記 2013/10/24】
サンプルをアップしました。
https://github.com/pospome/DropzoneJsSample


【追記 2013/09/13】
CSSの設定を追記しました。
基本的な使い方を書きました。
http://d.hatena.ne.jp/pospome/20130913/1379050713


dropzone.jsはAjaxを利用した非同期ファイルアップロードライブラリ。
http://www.dropzonejs.com

デモを見るとかなりいい感じ。
アップロード中のプログレスバー表示などデザインもちゃんとしている。
jQueryに依存しないというのも環境によっては嬉しい。

ただ、dropzone.jsのデフォルトデザインを活かしたまま、ちょっと手を加えようとすると
ハマってしまったのでメモ。

以下はdropzone.jsのデフォルトデザインを活かしたまま、ちょっと手を加えたい人向けの内容です。
dropzone.js の基本的な使い方は公式ドキュメントや他のサイトで確認して下さい。

今回はデフォルトのデザインを有効にしたまま以下を実装します。
1.ラベルの文言やアップロードファイルサイズの上限を設定する。
2.ファイルをドロップするエリアとサムネイルをプレビューするエリアを分ける。
3.各種イベントを補足する。

対象となる dropzone.js のバージョンは3.5.3 です。
jQueryを併用しています。
以下のupload.js と index.php を確認しながら説明を見たほうがいいと思う。

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title></title>
	<link rel="stylesheet" href="./css/dropzone.css"/>
	<script src="./jquery.js"></script>
	<script src="./dropzone.js"></script>
	<script src="./upload.js"></script>

	<style>
		#image_drop_area{
			background-color:#ffffe0;
			width:300px;
			height:200px;
		}
		#preview_area{
			background-color:#e6e6e6;
			min-height:200px;
			width:600px;
		}
	</style>
</head>
<body>

<div id="image_drop_area">DROP ZONE</div>

<br><br>

<h2>PrevewArea</h2>
<div id="preview_area" class="dropzone-custom"></div>

</body>
</html>
$(function(){
	$('#image_drop_area').dropzone({
		url:'./api.php',
		paramName:'file',
		maxFilesize:1, //MB
		addRemoveLinks:true,
		previewsContainer:'#preview_area',
		thumbnailWidth:100, //px
		thumbnailHeight:100, //px
		uploadprogress:function(_file, _progress, _size){
			_file.previewElement.querySelector("[data-dz-uploadprogress]").style.width = "" + _progress + "%";
		},
		success:function(_file, _return, _xml){
			//引数の _return には サーバ側 で出力(echo or print)された値が格納される。
			//サーバ側のエラーを検知するのに使うといい。
			_file.previewElement.classList.add("dz-success");
		},
		error:function(_file, _error_msg){
			var ref;
			(ref = _file.previewElement) != null ? ref.parentNode.removeChild(_file.previewElement) : void 0;
		},
		removedfile:function(_file){
			var ref;
			(ref = _file.previewElement) != null ? ref.parentNode.removeChild(_file.previewElement) : void 0;
		},
		previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n  <div class=\"dz-details\">\n    <div class=\"dz-filename\"><span data-dz-name></span></div>\n    <div class=\"dz-size\" data-dz-size></div>\n    <img data-dz-thumbnail />\n  </div>\n  <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress></span></div>\n  <div class=\"dz-success-mark\"><span>&#10004;</span></div>\n  <div class=\"dz-error-mark\"><span>&#10008;</span></div>\n  <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
		dictRemoveFile:'削除',
		dictCancelUpload:'キャンセル'
	});
});

ということで、説明。

1.ラベルの文言やアップロードファイルサイズの上限を設定する。
これは簡単。
dropzoneオブジェクトにプロパティを設定するだけ。
サンプルソースだと「URL」「サムネイルの大きさ」「アップロード上限サイズ」などを設定している。
公式ドキュメント通り設定すればOK。(英語だけど、頑張って読む)


2.ファイルをドロップするエリアとサムネイルをプレビューするエリアを分ける。
プレビューエリアは「previewsContainer」で設定できる。
CSSセレクター記法でOK。
今回はdivを指定している。
デフォルトCSSを有効にするにはプレビューのdivに class="dropzone" を指定する必要があるが、
class="dropzone" があると、そのdivにdropzone.jsが自動的にアップロードフォームを作成してしまうので、
dropzone.jsの読み込み段階でエラーになってしまう。
つまり、アップロード用のdivがあるとプレビュー用のdivに class="dropzone" を指定できない。
なので、デフォルトCSSの「.dropzone」を「.dropzone-custom」に変更し、
プレビュー用divも class="dropzone-custom"にする。
こうするとCSSが効く。

【追記 2013/09/13】
「.dropzone」を置換する時は「.dropzone 」のように末尾にスペースを入れるとちゃんと置換出来る。
末尾にスペースを入れないと、「dropzone-preview」というクラスも置換対象になってしまう。
置換は「dropzone.css」と「basic.css」ですること。
画像は「basic.css」で url で検索をかけてパスを正しく置換する。



3.各種イベントを捕捉する。
各種イベントはdropzoneオブジェクトに「success」「error」などのプロパティを設定し、
無名関数にしてやれば捕捉できる。
ただ、イベントを捕捉するとDOM操作が実行されなくなった。
removedfileイベントを捕捉するとプレビューが削除されなくなる。
これは各種イベントをdropzoneオブジェクトに設定したために
オーバーライドされているっぽい。
なので、設定した各種イベントにライブラリ中の同イベントのDOM操作をコピペして実装すると(当然)ちゃんと動く。

ちなみに、errorイベントはファイルのアップロードが成功したか、失敗したかは検知しない。
dropzoneオブジェクトで設定したファイル容量制限とかに引っかかった場合に検知する。
なので、ファイルが正常にアップロードされたかどうかはdropzoneオブジェクトのsuccessイベントへ返す必要がある。
successイベントの第2引数はサーバからのレスポンスが返ってくるので、
エラーの場合はサーバ側でエラーコードとかエラーメッセージを返しておけばいい。
PHPだと echo とかで返せる。

以上。

この記事を書く前に dropzone.js のバージョンが上がって、
デザインがカッコよくなった。
バージョンによって色々変わってくると思うので、
この記事と併せて最新の公式ドキュメントを確認した方がいい。