Битва файловых операций FileAPI "HTML5"

JavaScript

Эта статья взята из"Бой файловых операций FileAPI", остальные серии помещаются вGithub

Добро пожаловать в Exchange и Star

представлять

HTML5 предоставляет нам спецификации, связанные с File API. В основном участвуетФайловый интерфейса такжеОбъект FileReader.

В этой статье рассматриваются общие операции с файлами во внешнем интерфейсе при разработке, такие как обнаружение совместимости, выбор файла, чтение атрибутов, чтение файла, мониторинг хода выполнения, загрузка больших сегментов файлов и загрузка с помощью перетаскивания.

Готов к работе

Во-первых, наш файл исходит из<input>Список файлов, выбранных на вкладке. Итак, подготовьте следующий HTML-код:

<input type="file" id="files" multiple />
<div id="list"></div>
<div id="images"></div>
<!-- File API相关操作写在了script.js中 -->
<script src="./script.js"></script>

Проверить совместимость

Файловые объекты представляют собой особый тип BLOB-объектов. При входе в скрипт следует проверить, поддерживает ли текущий браузер File API:

if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
  throw new Error("当前浏览器对FileAPI的支持不完善");
}

Выбор файла монитора

Для типа для типа файла<input>тег, который срабатывает при выборе файлаchangeмероприятие. Информация о файле, выбранная пользователем, также будет передана в первый параметр функции обратного вызова.

function handleFileSelect(event) {
  const { files } = event.target;
  if (!files.length) {
    console.log("没有选择文件");
    return;
  }

  console.log("选中的文件信息是:", files);
}

document
  .querySelector("#files")
  .addEventListener("change", handleFileSelect, false);

Свойства файла - Файл

event.target.filesЯвляетсяFileListобъект, представляющий собойFileСписок объектов.

Каждый объект файла содержит свойства выбранного соответствующего файла. Обычно используется:

  • имя: имя файла
  • тип: тип файла
  • размер: размер файла

Ниже с помощью атрибута type отфильтруйте файлы, не относящиеся к типу изображения, и отобразите только информацию о файлах типа изображения:

function handleFileSelect(event) {
  const { files } = event.target;
  if (!files.length) {
    console.log("没有选择文件");
    return;
  }

  const innerHTML = [];
  const reImage = /image.*/;

  for (let file of files) {
    if (!reImage.test(file.type)) {
      continue;
    }

    innerHTML.push(
      `
      <li>
        <strong>${file.name}</strong>
        (${file.type || "n/a"}) -
        ${file.size} bytes
      </li>
      `
    );
  }

  document.querySelector("#list").innerHTML = `<ul>${innerHTML.join("")}</ul>`;
}

Прочитать файл - FileReader

В качестве примера возьмите чтение изображений, прочитайте и отобразите файлы всех типов изображений.

Чтение файла требует использованияFileReaderобъект, который обычно использует 3 метода обратного вызова:

  • onload: чтение файла завершено
  • onloadstart: начинается загрузка файла
  • onprogress : срабатывает во время загрузки файла

а такжеImageАналогично перед чтением файла нужно привязать обработку событий. Его операции чтения: readAsArrayBuffer, readAsDataURL, readAsBinaryString, readAsText. Переданный параметрFileобъект.

Так в чем же разница между этими методами?Различные методы чтения, callback-событияonloadполученоevent.target.resultне то же самое. Например,readAsDataURLЕсли вы читаете, Результат - это URL-адрес изображения.

Ниже приведен пример чтения файла изображения и его отображения:

function handleFileSelect(event) {
  let { files } = event.target;
  if (!files.length) {
    return;
  }

  let vm = document.createDocumentFragment(),
    re = /image.*/,
    loaded = 0, // 完成加载的图片数量
    total = 0; // 总共图片数量

  // 统计image文件数量
  for (let file of files) {
    re.test(file.type) && total++;
  }

  // onloadstart回调
  const handleLoadStart = (ev, file) =>
    console.log(`>>> Start load ${file.name}`);
  // onload回调
  const handleOnload = (ev, file) => {
    console.log(`<<< End load ${file.name}`);

    const img = document.createElement("img");
    img.height = 250;
    img.width = 250;
    img.src = ev.target.result;
    vm.appendChild(img);

    // 完成加载后,将其放入dom元素中
    if (++loaded === total) {
      document.querySelector("#images").appendChild(vm);
    }
  };

  for (let file of files) {
    if (!re.test(file.type)) {
      continue;
    }

    const reader = new FileReader();
    reader.onloadstart = ev => handleLoadStart(ev, file);
    reader.onload = ev => handleOnload(ev, file);
    // 读取文件对象
    reader.readAsDataURL(file);
  }
}

document
  .querySelector("#files")
  .addEventListener("change", handleFileSelect, false);

Следите за ходом чтения

При наблюдении за ходом чтения в основном выполняется обработка файлов на объекте FileReader.onprogressмероприятие.

В следующем примере откройте файл большего размера, чтобы увидеть эффект (в противном случае он будет прочитан целиком):

function handleFileSelect(event) {
  let { files } = event.target;
  if (!files.length) {
    return;
  }

  const handleLoadStart = (ev, file) =>
    console.log(`>>> Start load ${file.name}`);
  const handleProgress = (ev, file) => {
    if (!ev.lengthComputable) {
      return;
    }
    // 计算进度,并且以百分比形式展示
    const percent = Math.round((ev.loaded / ev.total) * 100);
    console.log(`<<< Loding ${file.name}, progress is ${percent}%`);
  };

  for (let file of files) {
    const reader = new FileReader();
    reader.onloadstart = ev => handleLoadStart(ev, file);
    reader.onprogress = ev => handleProgress(ev, file);
    reader.readAsArrayBuffer(file);
  }
}

document
  .querySelector("#files")
  .addEventListener("change", handleFileSelect, false);

читать большие файлы

Для больших файлов обычно используется идея загрузки в несколько частей для решения проблемы. Как упоминалось в начале статьи, File — это частный случай Blob. И у Блоба естьметод среза, через который фронтенд может реализовать операцию чтения больших файлов в шардах.

Для удобства объяснения сначала подготовьте файл txt, содержимое файла:hello world.

Пример кода выглядит следующим образом.В коде читаются только первые 5 байтов.Поскольку каждая английская буква занимает 1 байт, результатом печати должно быть "hello".

function handleFileSelect(event) {
  let { files } = event.target;
  if (!files.length) {
    return;
  }
  // 为了方便说明,这里仅仅读取第一个文件
  const file = files[0];
  // 读取前5个字节的内容
  const blob = file.slice(0, 5);

  const reader = new FileReader();
  // 控制台输出结果应该是:hello
  reader.onload = ev => console.log(ev.target.result);
  reader.readAsText(blob);
}

document
  .querySelector("#files")
  .addEventListener("change", handleFileSelect, false);

перетащить загрузить

Это точно так же, как File API, описанный ранее. Единственное, что требует специальной обработки, это то, что запись доступа к файловому объекту изменилась. для<input>Тег, прослушивание событий onchange, FileList хранится в event.target.files, для операций перетаскивания FileList хранится в параметре функции обратного вызова события перетаскивания, доступ к которому можно получить через event.dataTransfer.files.

Нужно изменить html-код:

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <style>
    #container {
      width: 300px;
      height: 300px;
      border: 3px dotted red;
    }
  </style>
</head>
<body>
  <div id="container"></div>
  <script src="./script.js"></script>
</body>
</html>

Код файла сценария выглядит следующим образом:

function handleDropover(event) {
  event.stopPropagation();
  event.preventDefault();
}

function handleDrop(event) {
  event.stopPropagation();
  event.preventDefault();
  /***** 访问拖拽文件 *****/
  const files = event.dataTransfer.files;
  console.log(files);
  /**********/
}

const target = document.querySelector("#container");
target.addEventListener("dragover", handleDropover);
target.addEventListener("drop", handleDrop);

Связанный с серверной частью

Связанный с серверной частью выходит за рамки этой статьи, вы можете обратиться кэта статья.