Ajaxを使わずに画面遷移なしで画像ファイルをアップロード(IE9対応版)

【告知】 10/14(土)新潟県上越市でIT勉強会を開催します!!

スポンサーリンク

今日は画像ファイルのアップロードを実装する方法のご紹介です。
ファイルアップロード時の画面遷移はしないケースで考えます。1ページ完結型です。
Ajaxは使わず、シンプルに通常のフォーム送信で実装します。

やり方

ファイル送信自体にはフォーム要素を使います。

<form id="FileUpload" name="upload" method="post" action="/api/upload" target="upload-image" enctype="multipart/form-data">
    <input type="file" name="image" />
    <input type="submit" name="submit" value="送信" />
</form>

<iframe id="FileUploadIframe" name="upload-image" style="display: none;"></iframe>

ここで重要なのは、非表示のiframeを配置することと、
フォーム要素のtarget属性値にiframeのname属性を指定して、iframeにフォームでのやりとりを任せてしまうことです。

これで普通にフォーム送信をして、サーバからはレスポンスとしてHTMLを返してもらいます。
JSONを返してもらいたい場合はiframeからJSONを受け取れるようにscriptタグの中でメソッドを定義してその中に格納してしまいましょう。

<!-- サーバが返すHTML -->

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <script>
            // iframeの中で呼ばれるのでwindow.parentで親フレームからアクセスできるようにする
            window.parent &&
            window.parent.Global &&
            window.parent.Global.sendJSON &&
            window.parent.Global.sendJSON({
                "meta": {
                    "code": 200,
                    "status":"success"
                },
                "content": {
                    "id": "*********"
                }
            });
        </script>
    </body>
</html>

イメージとしてはJSONPに近いですね。

返り値の処理はあらかじめwindow.Global.sendJSONというメソッドをグローバルに用意しておきます。

window.Global.sendJSON = function(data) {

    var response = data.content;

    if (data.meta.status === 'success') {
        // 通信成功時の処理
    } else {
        // 通信失敗時の処理
    }

};

サーバからレスポンスがない場合を想定してタイムアウトを設定しておくとより親切です。
アップロードに時間がかかることも考慮すると、ファイルサイズの上限を決めてしまうのもアリだと思います。

ファイルプレビューを表示したい

FileAPIを使うと簡単に実装できます。(注:IE10以上対応

HTML

<form id="FileUpload" name="upload" method="post" action="/api/upload" target="upload-image" enctype="multipart/form-data">
    <input type="file" name="image" />
    <input type="submit" name="submit" value="送信" />
</form>

<iframe id="FileUploadIframe" name="upload-image" style="display: none;"></iframe>

<!-- プレビュー挿入用の要素を用意する -->
<div id="FileUploadPreview"></div>

Javascript

var form = document.forms.upload,
    input = form.input,
    submit = form.submit,
    preview = doc.getElementById('FileUploadPreview');

function preview(file) {
    if (file.type.match(/image/)) {
        var fr = new FileReader();

        fr.onload = function(e) {
            var img = new Image();
            img.src = e.target.result;
            preview.innerHTML = '';
            preview.appendChild(img);
        };
        fr.readAsDataURL(file);
    }
}

if (!window.File) {
    return;
} else {
    submit.addEventListener('click', function(e) {
        var file = input.files[0];
        preview(file);
    }, false);
}

IE9以下もサポートする場合は、フォーム送信時にサーバからプレビュー用画像を返してもらい表示しましょう。


イソップへのお悩み相談募集中

イソップに相談しませんか?

当ブログで紹介しているような、Web制作やフリーランスへの悩みをイソップに相談してみませんか?
回答できることがあれば記事の中でご紹介します。