Использование readAsDataURL() для предварительного просмотра изображения

jsFiddle URL: http://jsfiddle.net/Xotic750/AjtLx

Работал над этим весь день, и я не вижу проблемы. Вероятно, из-за моего узкого понимания того, как работают объекты FileReader, но что я пытаюсь сделать, это использовать readAsDataURL() для получения изображений, которые пользователь выбрал, и просмотреть их на экране в таблице. Все работает минус... вы догадались... предварительный просмотр... ну вроде. Я думаю, что я близок, потому что предварительный просмотр будет работать, НО он отображает только последний образ набора. Скажем, например, если бы я загрузил 6 изображений, то первая строка из 3 изображений была бы сломана, вторая строка первая 2 была бы сломана, тогда окончательное 6-е изображение отобразило бы предварительный просмотр.... Любые советы были высоко оценены. Кроме того, как только это сработает, это может помочь другим, пытающимся сделать то же самое, потому что я искал все решения для этой проблемы, и я не могу что-то выкопать....

function PreviewImages() {
    var inputID = document.getElementById('input_clone');
    var totalImages = inputID.files.length;
    var imagesPerRow = 3;
    var numRows = totalImages / imagesPerRow;
    var row = "";
    var cell = "";
    var element1 = "";
    var elementID = "";


    for(var i = 0; i < numRows; i++){ //create rows
        row = document.getElementById('image_preview_table').insertRow(i);
        for(var ii = 0; ii < imagesPerRow; ii++){ //create cells
            cell = row.insertCell(ii);
            elementID = "img_" + ii;
            element1 = document.createElement("img");
            element1.name = elementID;
            element1.id = elementID
            cell.appendChild(element1);

            oFReader = new FileReader();

            oFReader.onload = function(oFREvent){
                var dataURI = oFREvent.target.result;
                var image = document.getElementById(elementID);
                image.src = dataURI;
            };

                oFReader.readAsDataURL(document.getElementById("input_clone").files[ii]);

    }
}
}

Ответ 1

Вот решение, в оригинале было внесено немного корректировки, чтобы заставить его работать, как вы, вероятно, заметите.

CSS

div.rounded {
    width: 100%;
    border-style: solid;
    border-width: 1px;
    border-radius: 5px;
}
label {
    display: block;
}
input {
    display: block;
}
#previewTable {
    width: 100%;
}

HTML

<div id="imagesDiv" class="rounded">
    <label for="chooseFiles">Add Images</label>
    <input type="file" id="chooseFiles" multiple="multiple" />
    <table id="previewTable">
        <thead id="columns"></thead>
        <tbody id="previews"></tbody>
    </table>
</div>

Javascript

(function (global) {
    var imagesPerRow = 3,
        chooseFiles,
        columns,
        previews;

    function PreviewImages() {
        var row;

        Array.prototype.forEach.call(chooseFiles.files, function (file, index) {
            var cindex = index % imagesPerRow,
                oFReader = new FileReader(),
                cell,
                image;

            if (cindex === 0) {
                row = previews.insertRow(Math.ceil(index / imagesPerRow));
            }

            image = document.createElement("img");
            image.id = "img_" + index;
            image.style.width = "100%";
            image.style.height = "auto";
            cell = row.insertCell(cindex);
            cell.appendChild(image);

            oFReader.addEventListener("load", function assignImageSrc(evt) {
                image.src = evt.target.result;
                this.removeEventListener("load", assignImageSrc);
            }, false);

            oFReader.readAsDataURL(file);
        });
    }

    global.addEventListener("load", function windowLoadHandler() {
        global.removeEventListener("load", windowLoadHandler);
        chooseFiles = document.getElementById("chooseFiles");
        columns = document.getElementById("columns");
        previews = document.getElementById("previews");

        var row = columns.insertRow(-1),
            header,
            i;

        for (i = 0; i < imagesPerRow; i += 1) {
            header = row.insertCell(-1);
            header.style.width = (100 / imagesPerRow) + "%";
        }

        chooseFiles.addEventListener("change", PreviewImages, false);
    }, false);
}(window));

Вкл jsfiddle

Ответ 2

Проблема с вашим кодом: readAsDataURL() является асинхронным, вы должны подождать, пока он закончит чтение, прежде чем вы вызовете второе чтение или создадите новый экземпляр, вызвав новый файл FileReader().

Ответ Xotic750 работает, потому что он создает один FileReader для каждого изображения, в то время как вы использовали только один FileReader.

Но использование FileReader для предварительного просмотра изображений не является хорошим выбором, так как FileReader.readAsDataURL() преобразует все изображение в большую строку (в виде "data: image/jpeg; base64,/9j/4SVaRXhpZgAAS......" ), и вы показываете изображение, помещая всю строку данных изображения в атрибут img.src, если ваше изображение велико, вы рискуете исчерпать память.

img.src должен содержать URL-адрес изображения, а не данные изображения, хотя вы можете назначить URL-адрес, содержащий все данные изображения, через img.src= "data: image/jpeg;......".

Итак, вы должны использовать window.URL.createObjectURL() для создания URL-адреса, ссылающегося на ваш локальный образ, и назначить этот URL-адрес img.src:

...
img.src = window.URL.createObjectURL(fileInput.files[i]);
...