15

IE で動作するファイル アップロード スクリプトを書きたいのですが、書いている 2 種類のコードは IE で問題があります。

助けてください。IE で動作するファイル アップロード スクリプトを作成するにはどうすればよいですか?

Type 1
問題 IE で File Api をサポートしていない (使わないのがコツ?)

    <!DOCTYPE html>

<html>
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.6.2.js" type="text/javascript"></script>
    <script type="text/javascript">
        function updateSize() {
            var nBytes = 0;
            var nFiles=0;
            oFiles = document.getElementById("uploadInput").files;
            nFiles = oFiles.length;
            for (var nFileId = 0; nFileId < nFiles; nFileId++) {
                nBytes += oFiles[nFileId].size;
            }
            var sOutput = nBytes + " bytes";
            // optional code for multiples approximation
            for (var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; nApprox > 1; nApprox /= 1024, nMultiple++) {
                sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";
            }
            document.getElementById("fileNum").innerHTML = nFiles;
            document.getElementById("fileSize").innerHTML = sOutput;
        }
        // end of optional code
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <p><input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple /> selected files: <span id="fileNum">0</span>; total size: <span id="fileSize">0</span></p>
<p><input type="submit" value="Send file"></p>
    </form>
</body>
</html>

タイプ 2
問題 サポートされていない document.getElementById('fileToUpload') .files[0] (Get Files[0] を取得しないというトリックですか?)

 <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        function fileSelected() {
            var file = document.getElementById('fileToUpload').files[0];
            if (file) {
                var fileSize = 0;
                if (file.size > 1024 * 1024)
                    fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
                else
                    fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

                document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
                document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
                document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
            }
        }

        function uploadFile() {
            var fd = new FormData();
            fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
            var xhr = new XMLHttpRequest();
            xhr.upload.addEventListener("progress", uploadProgress, false);
            xhr.addEventListener("load", uploadComplete, false);
            xhr.addEventListener("error", uploadFailed, false);
            xhr.addEventListener("abort", uploadCanceled, false);
            $.post("UploadHandler.ashx");
            //xhr.open("POST", "UploadHandler.ashx");
            xhr.send(fd);
        }

        function uploadProgress(evt) {
            if (evt.lengthComputable) {
                var percentComplete = Math.round(evt.loaded * 100 / evt.total);
                document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
                document.getElementById('prog').value = percentComplete;
            }
            else {
                document.getElementById('progressNumber').innerHTML = 'unable to compute';
            }
        }

        function uploadComplete(evt) {
            /* This event is raised when the server send back a response */
            alert(evt.target.responseText);
        }

        function uploadFailed(evt) {
            alert("There was an error attempting to upload the file.");
        }

        function uploadCanceled(evt) {
            alert("The upload has been canceled by the user or the browser dropped the connection.");
        }
    </script>

</head>
<body>
    <form id="form1">
    <div>
        <label for="fileToUpload">
            Select a File to Upload</label>
        <input type="file" name="fileToUpload[]" id="fileToUpload" onchange="fileSelected();" />
    </div>
    <div id="fileName">
    </div>
    <div id="fileSize">
    </div>
    <div id="fileType">
    </div>
    <div>
        <input type="button" onclick="uploadFile()" value="Upload" />
    </div>
    <div id="progressNumber">
    </div>
    <progress id="prog" value="0" max="100.0"></progress>
    </form>
</body>

助けてください :(

4

1 に答える 1

53

これらの機能は、IE10 またはその他の最新のブラウザーを使用していない限り使用できません。以前のバージョンの Internet Explorer (およびその他のブラウザー) でも回避策は可能ですが、バックエンド コードも調整する必要があります。

うまくいかない理由

バージョン 10 までの Internet Explorer は、これらの機能の多くをサポートしていません。主要な機能はFormDataおよびFileReader API です。どちらのコード スニペットもFileReaderAPI に依存しており、2 番目のコード スニペットもFormData動的にファイルをアップロードするために依存しています。

コードを実行するかどうかを決定する方法

私は最近、これらの機能を検出し、サポートに応じて異なるコードを提供するファイル アップロード ウィジェットを作成しました。Modernizrの機能検出を使用しました。これは、テストがオープン ソース コミュニティによって定期的にテストされているためです。

var support  = {
  // Are files exposed to JS?
  // As used by Modernizr @
  // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/file/api.js
  'fileReader'  : (function testFileReader(){
    // Test: look for global file class.
    return !!(window.File && window.FileList && window.FileReader);
  }()),

  // AJAX file upload via formData?
  'formData'    : window.FormData !== void 0
};

関数については、評価fileSelectedする必要があります。のために、あなたが必要です。support.fileReadertrueuploadFilesupport.formData

これらの機能をサポートしていないブラウザーの回避策

これらの機能がなければ、フロントエンドからファイルを読み取ったり、AJAX を使用してファイルを送信したりすることはできません。<iframe/>ただし、現在のページ内の非表示を介してファイルを送信し、UploadHandler.ashxXHR 以外のリクエストに対して別の方法で応答することができます。

このソリューションは技術的には同期的 (別の非表示のページで発生するだけ) であるため、更新は取得されません。唯一のフィードバックは、アップロードが完了し、サーバーが応答したときです。そのため、ユーザーがファイルを完全にアップロードしてから、ファイル名、サイズ、および成功についてのみユーザーに通知できます。これには時間がかかる場合があります。

とにかく、これの HTML は次のようになります。

<form 
  id="form1" 
  runat="server" 
  action="UploadHandler.ashx"
  target="fileIframe">
  <iframe 
    name="fileIframe"
    style="display:none"
    onload="parseIframeResponse"
    tabindex="-1">
  </iframe>
  <p>
    <input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple />
    selected files: 
    <span id="fileNum">
      0
    </span>
    ; total size: 
    <span id="fileSize">
      0
    </span>
  </p>
  <p>
    <input type="submit" value="Send file">
  </p>
</form>

いくつかの変更:

  1. フォームに が追加されました。これtargetは、そのコンテンツを の URI に投稿するとaction、現在のページではなく、そこに応答が読み込まれることを意味します。
  2. ターゲットは、name含まれている iframe への参照です。で隠され、ユーザーがつまずかないようにdisplay:noneネガが付けられます。プロパティtabindexも指定されています。onloadこれは、古いバージョンの IE で関数を load イベントにバインドする唯一の方法です。

したがって、フォームが送信されると、現在のページにとどまり、サーバーの応答が非表示の iframe に読み込まれます。その場合、ブラウザはonload属性で指定された関数を実行します。悲しいことに、これは関数がグローバルスコープにある必要があることを意味します!

バックエンドのもの

あなたのバックエンドがどのように機能するかはわかりませんが、iframe が応答をダウンロードする代わりにロードする場合、それは HTML またはプレーン テキストである必要があります (MIME タイプで指定する必要があります)。ヘッダーを探すことで、バックエンドから AJAX 経由でフォームが投稿されたかどうかを確認できます。X-Requested-Withヘッダーの値がXMLHttpRequest存在しない場合は、iframe が応答を要求しており、テキストまたは送信する必要があります。 HTML。fileNamefileSize&など、ユーザーにフィードバックしたい値を公開する JSON 応答を文字列化することができますfileType。これを自分で行うか、同僚に処理してもらいたいと思っています。

iframe レスポンスのキャプチャ

前述のように、onload古い IE は非常に風変わりであるため、応答ハンドラー関数は属性をバインドするグローバル スコープ内にある必要があります。jQuery を使用していることがわかりました。サーバーの応答を文字列化するルートをたどった場合は、この関数を次のように記述できます。

function parseIframeResponse(){
  var response = $('#fileIframe').contents().find('body').text();
  var object   = $.parseJSON(response);
}

iframeloadイベント バインディングに関する問題

前述のように、iframe の読み込みイベントは、iframe 自体の属性としてインラインでバインドする必要があります。これは、IE が単に登録に失敗するためです。しかし、空の iframe (空のまたは存在しないsrcものはデフォルトでabout:blank) でもロード イベントが発生するため、これ自体に問題があります。これを軽減するresponseには、空の文字列を誤検知として評価するものをすべて破棄し、障害が発生した場合でもバックエンドが何らかのコンテンツで応答するようにする必要があります。

fileSelectedおそらく、そこにある情報を使用して、関数、uploadProgressなどで現在取得しているコードの一部を実行したいと思うでしょう。

お役に立てれば。

編集 1: すぐに使えるソリューション

後から考えると、問題に対する独自の解決策を開発したことを理由にこれを書いたにもかかわらず、 Fine Uploaderは言うまでもなく過失と見なされる可能性があります IE7 以降で可能な限り最高のファイル アップロード エクスペリエンスを実現します。また、アップロードを解析するためのバックエンド サーバー コンポーネント (ASP.NET など) も適切に選択されています。独自にロールするよりも、これを微調整する方が簡単な場合があります。

編集 2: iframe のloadイベントに関する問題について言及することを怠った。回答を修正しました。

于 2013-03-27T17:52:20.267 に答える