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

今日は画像ファイルのアップロードを実装する方法のご紹介です。
ファイルアップロード時の画面遷移はしないケースで考えます。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以下もサポートする場合は、フォーム送信時にサーバからプレビュー用画像を返してもらい表示しましょう。

五十川 洋平(Yohei Isokawa)

五十川 洋平(Yohei Isokawa)

フロントエンドエンジニア/面白法人カヤックなどのWeb制作会社に勤務したのち、故郷の新潟に戻り独立。JSフレームワークAngularやFirebase、Google Cloud Platformを使ったWebアプリ開発が得意。 また、Udemyのプログラミング解説の講師、writer.appの自主開発や上越TechMeetupの主催などを行っています。

プロフィール

©Copyright 2022 Yohei Isokawa All Rights Reserved.