Поле файлу не працює з v-model - значення <input type="file"> можна лише прочитати:
<script setup lang="ts">
import { ref } from 'vue'
import axios from 'axios'
const file = ref<File | null>(null)
const progress = ref(0)
function onChange(e: Event) {
file.value = (e.target as HTMLInputElement).files?.[0] ?? null
}
async function upload() {
if (!file.value) return
const data = new FormData()
data.append('avatar', file.value)
data.append('title', 'Аватар')
await axios.post('/api/avatar', data, {
onUploadProgress: (e) => {
progress.value = e.total ? Math.round((e.loaded / e.total) * 100) : 0
},
})
}
</script>
<template>
<input type="file" accept="image/*" @change="onChange" />
<progress v-if="progress" :value="progress" max="100" />
<button @click="upload">Завантажити</button>
</template>
Головні моменти:
FormDataформує запитmultipart/form-data. ЗаголовокContent-Typeне встановлюють вручну - браузер сам додає його з правильнимboundary. РучнийContent-Type: multipart/form-dataбезboundary- сервер не розбере тіло;- прогрес завантаження дає
XMLHttpRequest(подіяupload.onprogress), і саме його використовує axios у браузері. Уfetchпрогресу відправки немає - лише прогрес отримання відповіді через потоки; PUT/PATCHз файлом у Laravel: PHP не розбираєmultipartдля цих методів. ВідправляйтеPOSTз полем_method=PUT(method spoofing).
Попередній перегляд зображення:
const preview = ref<string | null>(null)
watch(file, (f, _, onCleanup) => {
if (!f) return
const url = URL.createObjectURL(f)
preview.value = url
onCleanup(() => URL.revokeObjectURL(url)) // звільнити пам'ять
})
Великі файли:
- скасування -
AbortControllerіsignalв опціях axios, щоб користувач міг зупинити завантаження; - ліміти:
upload_max_filesizeіpost_max_sizeу PHP,client_max_body_sizeу Nginx - помилка413чи порожній$request->file()часто означає саме це; - пряме завантаження в сховище: сервер видає підписаний URL S3/R2, браузер вантажить файл туди напряму, а застосунку повідомляє лише ключ. PHP не тримає гігабайти в пам'яті й не впирається в тайм-аути;
- частинами (chunked upload, протокол tus) - для дуже великих файлів і нестабільних з'єднань.
Перевірка на клієнті (accept, розмір файлу) - для зручності; сервер усе одно валідує тип і розмір (mimes, max).