html5では、file apiが追加された為、ドラッグアンドドロップでfileを開けるようになったようなので、試しに書いてみました。
※html5では、FileReaderクラスとFormDataクラスを使うようですが、firefox3.6では、FormDataが使用できないようなので、base64形式+jquery.param()なデータをjquery.post()でアップロードしています。
※drag&dropでは画像のサムネイルやテキストファイルの内容もプレビューできます
サーバ側の動作は確認していませんが、なんとなく理解できた気がします。
<html> <head> <meta charset="utf-8"> <title>drag & drop file upload</title> <script type="text/javascript" src="jquery-1.4.4.min.js"></script> <link rel="stylesheet" href="common.css"/> </head> <body> <div id="container"> <div id="drop_here"> ここにfileをdrag & drop して下さい </div> <input type="button" value="表示中のFILEをUPLOAD" onclick='fup.upload_files()'> <div style="clear:both"></div> <div id="files_info"> </div> </div> <script type="text/javascript" src="FileUpload.js"></script> </body> </html>
function FileUpload(elm_id){ var LOADED_FILES = []; //upload対象のfile一覧 var LIMIT_IMG_W = 200; //画像fileはthumb nail表示しますが、 var LIMIT_IMG_H = 200; //その際の最大表示サイズ var UPLOAD_URL = 'http://ないしょ'; var TEXT_ENCODING = 'UTF-8'; //初期化 this.init = function(elm_id){ if( $("#" + elm_id).size() == 0 ){ alert("can't find drop to element id : " + elm_id); return; } LOADED_FILES = []; //drop eventをセット. //※jquery.bindを使用すると、drop eventからdataTransferを取得不可。 var this_obj = this; document.getElementById(elm_id) .addEventListener('drop', function(e){this_obj.do_drop_file(e);},false); //default event & bubblingを中止 $("#" + elm_id) .bind('dragenter', function(e){e.preventDefault(); e.stopPropagation();}) .bind('dragover', function(e){e.preventDefault(); e.stopPropagation();}); $("html") .bind('drop', function(e){e.preventDefault(); e.stopPropagation();}) .bind('dragenter', function(e){e.preventDefault(); e.stopPropagation();}) .bind('dragover', function(e){e.preventDefault(); e.stopPropagation();}); }; //fileがdropされると、呼ばれます this.do_drop_file = function(e){ var files = e.dataTransfer.files; var reader = new FileReader(); reader.onloadend = function(e) { LOADED_FILES.push(e.target.result); }; for (var i=0; i<files.length; i++){ if (files[i].size ==0) continue; reader.readAsDataURL(files[i]); //base 64でload $('#files_info').append($("<div class='file_info'>") ); //filenameやtype, sizeの表示 var file_info = "<span class='file_title'>" +files[i].name+"</span>"+ ' ( '+ files[i].type+' '+files[i].size+'byte)<br>'; $('#files_info>div:last').append(file_info); //thumb nailやtext内容の表示 if ( this.can_disp_image_file(files[i].type) ){ $('#files_info>div:last').append("<img>"); this.make_image_element(files[i], $('#files_info>div:last img')); } else if ( this.can_disp_text_file(files[i].type) ){ $('#files_info>div:last').append( "<textarea cols='80' rows='10'></textarea>"); this.make_text_element(files[i], $('#files_info>div:last textarea')); } } }; //thumb nail表示用のelement this.make_image_element = function(file,img){ var reader = new FileReader(); reader.onload = function(e) { //html5では、srcにbase64な値を登録できるらしい img.attr('src',e.target.result); if( img.attr('width') >= LIMIT_IMG_W ){ img.attr('width',LIMIT_IMG_W); } if ( img.attr('height') >= LIMIT_IMG_H ){ img.attr('height',LIMIT_IMG_H); } }; reader.readAsDataURL(file); //base 64形式でload return img; }; this.make_text_element = function(file,textarea){ var reader = new FileReader(); reader.onload = function(e) { $(textarea).html(e.target.result); }; reader.readAsText(file,TEXT_ENCODING); //text形式でload }; //表示可能な画像fileの判定 this.can_disp_image_file = function(file_type){ if (file_type == 'image/png' || file_type == 'image/jpeg' ){ return true; } return false; }; //表示可能な画像fileの判定 this.can_disp_text_file = function(file_type){ if (file_type == 'text/plain' ){ return true; } return false; }; //※html5では、FormDataというクラスが追加されたようですが // firefox3.6では利用できないようなので、jquery.param()で送信. this.upload_files = function(){ if (LOADED_FILES.length ==0) return; var data = new Object(); data.files = LOADED_FILES; var this_obj = this; $.post(UPLOAD_URL, $.param(data,true), function(data,textStatus){ this_obj.post_upload_files(data,textStatus); } ); }; this.post_upload_files = function(data,textStatus){ alert('UPLOAD完了'); }; //初期化実行 this.init(elm_id); }; var fup = new FileUpload('drop_here');
#container { padding: 5px; } #drop_here { border: 1px solid #000000; width: 250px; height: 50px; text-align: center; margin-right: 5px; padding: 5px; float:left; } .file_info { border: 1px solid #000000; margin: 5px 0; padding: 5px; }
iframeを用いた画面遷移なしアップロードもあるみたい
2012/8/28追記
クロスブラウザでファイルのドラッグ&ドロップ、Ajaxアップロードを可能にする「FileDrop」:phpspot開発日誌