Работа с файлами

Работа с файлами в Vue.js строится на взаимодействии компонентов с объектами File и FileReader браузера, а также с серверной частью через HTTP-запросы. Vue не предоставляет встроенных API для работы с файловой системой, но позволяет удобно интегрировать стандартные веб-технологии и библиотеки.


Загрузка файлов через <input type="file">

Для выбора файлов используется стандартный элемент формы:

<input type="file" @change="handleFileUpload" multiple>
  • Атрибут multiple позволяет выбирать несколько файлов.
  • Событие change срабатывает при выборе файлов пользователем.

В методе компонента можно получить доступ к файлам через event.target.files:

export default {
  methods: {
    handleFileUpload(event) {
      const files = event.target.files;
      for (let i = 0; i < files.length; i++) {
        console.log(files[i].name, files[i].size, files[i].type);
      }
    }
  }
}

Каждый элемент массива files является объектом File, содержащим свойства name, size, type, lastModified.


Чтение содержимого файлов с FileReader

Для чтения данных из файлов используется объект FileReader:

handleFileUpload(event) {
  const file = event.target.files[0];
  const reader = new FileReader();

  reader.onl oad = (e) => {
    console.log(e.target.result); // данные файла в виде строки
  };

  reader.readAsText(file); // чтение как текст
}

Методы чтения файлов:

  • readAsText(file) — текстовый формат.
  • readAsDataURL(file) — для изображений и файлов, возвращает base64.
  • readAsArrayBuffer(file) — бинарные данные.
  • readAsBinaryString(file) — устаревший, лучше использовать ArrayBuffer.

Двусторонняя привязка с файлами

Vue позволяет связывать выбранные файлы с данными компонента через реактивное состояние:

data() {
  return {
    uploadedFiles: []
  };
},
methods: {
  handleFileUpload(event) {
    this.uploadedFiles = Array.from(event.target.files);
  }
}

Array.from преобразует FileList в обычный массив, удобный для отображения и обработки в шаблоне.

<ul>
  <li v-for="file in uploadedFiles" :key="file.name">
    {{ file.name }} ({{ file.size }} байт)
  </li>
</ul>

Загрузка файлов на сервер

Для отправки файлов на сервер чаще всего используется FormData:

uploadFiles() {
  const formData = new FormData();
  this.uploadedFiles.forEach(file => {
    formData.append('files[]', file);
  });

  fetch('/upload', {
    method: 'POST',
    body: formData
  })
  .then(response => response.json())
  .then(data => {
    console.log('Успех:', data);
  })
  .catch(error => {
    console.error('Ошибка:', error);
  });
}

Особенности FormData:

  • Автоматически устанавливает заголовок Content-Type как multipart/form-data.
  • Позволяет прикреплять как одиночные файлы, так и массивы файлов.

Просмотр превью изображений

Для отображения изображений до отправки на сервер используется FileReader.readAsDataURL:

previewImage(event) {
  const file = event.target.files[0];
  const reader = new FileReader();

  reader.onl oad = (e) => {
    this.imagePreview = e.target.result;
  };

  reader.readAsDataURL(file);
}

Шаблон для превью:

<img v-if="imagePreview" :src="imagePreview" alt="Preview" />

Реактивное свойство imagePreview обновляется автоматически, и картинка появляется сразу после выбора файла.


Ограничение размеров и типов файлов

Для предотвращения загрузки больших файлов или неподходящих форматов используются проверки:

handleFileUpload(event) {
  const files = Array.from(event.target.files);
  this.uploadedFiles = files.filter(file => {
    const isValidType = ['image/jpeg', 'image/png'].includes(file.type);
    const isValidSize = file.size <= 2 * 1024 * 1024; // 2 МБ
    return isValidType && isValidSize;
  });
}

Это позволяет отказаться от файлов, не соответствующих требованиям, ещё на клиенте.


Асинхронная обработка файлов

Для обработки больших файлов рекомендуется использовать асинхронные функции и Promise:

async processFiles(files) {
  for (const file of files) {
    const content = await this.readFileAsync(file);
    console.log(content);
  }
},
readFileAsync(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onl oad = () => resolve(reader.result);
    reader.oner ror = reject;
    reader.readAsText(file);
  });
}

Это обеспечивает последовательное чтение файлов без блокировки основного потока и совместимо с современными подходами работы с async/await.


Использование сторонних библиотек

Vue легко интегрируется с библиотеками для работы с файлами:

  • Axios — для отправки FormData на сервер.
  • Vue-FilePond — красивый компонент для загрузки и предпросмотра файлов.
  • PapaParse — для парсинга CSV-файлов на клиенте.
  • JSZip — для создания и чтения ZIP-архивов.

Библиотеки позволяют ускорить разработку и расширяют функциональность без написания большого объёма кода.


Работа с drag-and-drop

Поддержка перетаскивания файлов реализуется через события dragover и drop:

<div 
  @dragover.prevent
  @drop.prevent="handleDrop"
  class="drop-zone">
  Перетащите файлы сюда
</div>

Метод обработки:

handleDrop(event) {
  const files = Array.from(event.dataTransfer.files);
  this.uploadedFiles = files;
}

Событие preventDefault необходимо, чтобы браузер не открывал файл по умолчанию.


Рекомендации по безопасности

  • Проверять тип и размер файлов на клиенте и сервере.
  • Никогда не доверять именам файлов пользователя при сохранении на сервере.
  • Использовать отдельные директории для загруженных данных.
  • Фильтровать потенциально опасные символы и расширения.