Ответ 3
Это длинный пост, но я устал от всех этих примеров, которые не работали для меня, потому что они использовали объекты Promise или странствующий this
, что имеет другое значение, когда вы используете Reactjs. Моя реализация использовала DropZone с responsejs, и я получил байты, используя фреймворк, подобный тому, что размещено на этом следующем сайте, когда ничего больше не будет работать: https://www.mokuji.me/article/drop-upload- учебник-1. Для меня было 2 ключа:
- Вы должны получить байты от объекта события, используя и во время функции onload FileReader.
-
Я пробовал различные комбинации, но в итоге работала:
const bytes = e.target.result.split('base64,')[1];
Где e
- событие. React требует const
, вы можете использовать var
в простом Javascript. Но это дало мне байтовую строку с кодировкой base64.
Поэтому я просто собираюсь включить применимые строки для интеграции этого, как если бы вы использовали React, потому что это то, как я его создавал, но попробуйте также обобщить это и добавить комментарии там, где это необходимо, чтобы применить его к ванильному Javascript реализация - предостерег, что я не использовал его так, как в такой конструкции, чтобы проверить его.
Это будут ваши привязки в верхней части, в вашем конструкторе, в структуре React (не относящейся к реализации JavaScript Javascript):
this.uploadFile = this.uploadFile.bind(this);
this.processFile = this.processFile.bind(this);
this.errorHandler = this.errorHandler.bind(this);
this.progressHandler = this.progressHandler.bind(this);
И у вас будет onDrop={this.uploadFile}
в элементе DropZone. Если вы делали это без React, это эквивалентно добавлению обработчика события onclick, который вы хотите запустить, когда вы нажимаете кнопку "Загрузить файл".
<button onclick="uploadFile(event);" value="Upload File" />
Затем функция (применимые строки... Я не буду менять свой индикатор выполнения загрузки и т.д.):
uploadFile(event){
// This is for React, only
this.setState({
files: event,
});
console.log('File count: ' + this.state.files.length);
// You might check that the "event" has a file & assign it like this
// in vanilla Javascript:
// var files = event.target.files;
// if (!files && files.length > 0)
// files = (event.dataTransfer ? event.dataTransfer.files :
// event.originalEvent.dataTransfer.files);
// You cannot use "files" as a variable in React, however:
const in_files = this.state.files;
// iterate, if files length > 0
if (in_files.length > 0) {
for (let i = 0; i < in_files.length; i++) {
// use this, instead, for vanilla JS:
// for (var i = 0; i < files.length; i++) {
const a = i + 1;
console.log('in loop, pass: ' + a);
const f = in_files[i]; // or just files[i] in vanilla JS
const reader = new FileReader();
reader.onerror = this.errorHandler;
reader.onprogress = this.progressHandler;
reader.onload = this.processFile(f);
reader.readAsDataURL(f);
}
}
}
Был этот вопрос по этому синтаксису для vanilla JS о том, как получить этот файловый объект:
JavaScript/HTML5/jQuery Drag-And-Drop Upload - "Uncaught TypeError: Невозможно прочитать файлы свойств" неопределенного "
Обратите внимание, что React DropZone уже помещает объект File в файл this.state.files
для вас, если вы добавляете files: [],
в ваш this.state = {.... }
в своем конструкторе. Я добавил синтаксис ответа на этот пост о том, как ваш объект File. Он должен работать, или есть другие сообщения, которые могут помочь. Но все, что Q/A сказал мне, это как получить объект File
, а не данные blob. И даже если я сделал fileData = new Blob([files[0]]);
как в ответе sebu, который по какой-то причине не включал var
с ним, он не рассказывал мне, как читать это содержимое blob и как это делать без объекта Promise. Так что, когда появился FileReader, хотя я действительно пытался и обнаружил, что я не мог использовать их readAsArrayBuffer
для любых изменений.
Вы должны будете иметь другие функции, которые идут вместе с этой конструкцией - один для обработки onerror
, один для onprogress
(как показано дальше, ниже), а затем основной, onload
, что на самом деле делает работу, как только метод на reader
вызывается в этой последней строке. В основном вы передаете свой event.dataTransfer.files[0]
прямо в эту функцию onload
, из того, что я могу сказать.
Поэтому метод onload
вызывает мою функцию processFile()
(только применимые строки):
processFile(theFile) {
return function(e) {
const bytes = e.target.result.split('base64,')[1];
}
}
А bytes
должны иметь байты base64.
Дополнительные функции:
errorHandler(e){
switch (e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
alert('File not found.');
break;
case e.target.error.NOT_READABLE_ERR:
alert('File is not readable.');
break;
case e.target.error.ABORT_ERR:
break; // no operation
default:
alert('An error occurred reading this file.');
break;
}
}
progressHandler(e) {
if (e.lengthComputable){
const loaded = Math.round((e.loaded / e.total) * 100);
let zeros = '';
// Percent loaded in string
if (loaded >= 0 && loaded < 10) {
zeros = '00';
}
else if (loaded < 100) {
zeros = '0';
}
// Display progress in 3-digits and increase bar length
document.getElementById("progress").textContent = zeros + loaded.toString();
document.getElementById("progressBar").style.width = loaded + '%';
}
}
И применимая индикация индикатора прогресса:
<table id="tblProgress">
<tbody>
<tr>
<td><b><span id="progress">000</span>%</b> <span className="progressBar"><span id="progressBar" /></span></td>
</tr>
</tbody>
</table>
И CSS:
.progressBar {
background-color: rgba(255, 255, 255, .1);
width: 100%;
height: 26px;
}
#progressBar {
background-color: rgba(87, 184, 208, .5);
content: '';
width: 0;
height: 26px;
}
Эпилог:
Внутри processFile()
по какой-то причине я не мог добавить bytes
в переменную I, вырезанную в this.state
. Поэтому вместо этого я устанавливаю его непосредственно в переменную, attachments
, которая была в моем объекте JSON, RequestForm
- тот же объект, что и мой this.state
. attachments
- это массив, поэтому я мог бы нажимать несколько файлов. Это было так:
const fileArray = [];
// Collect any existing attachments
if (RequestForm.state.attachments.length > 0) {
for (let i=0; i < RequestForm.state.attachments.length; i++) {
fileArray.push(RequestForm.state.attachments[i]);
}
}
// Add the new one to this.state
fileArray.push(bytes);
// Update the state
RequestForm.setState({
attachments: fileArray,
});
Затем, поскольку this.state
уже содержит RequestForm
:
this.stores = [
RequestForm,
]
Я мог бы сослаться на него, как this.state.attachments
оттуда на. Функция React, которая не применима в Vanilla JS. Вы можете построить аналогичную конструкцию в простом JavaScript с глобальной переменной и, соответственно, сделать гораздо проще:
var fileArray = new Array(); // place at the top, before any functions
// Within your processFile():
var newFileArray = [];
if (fileArray.length > 0) {
for (var i=0; i < fileArray.length; i++) {
newFileArray.push(fileArray[i]);
}
}
// Add the new one
newFileArray.push(bytes);
// Now update the global variable
fileArray = newFileArray;
Затем вы всегда просто ссылаетесь на fileArray
, перечисляете его для любых строк байтов файла, например var myBytes = fileArray[0];
для первого файла.