Это может быть не то, что вы ищете, но должно направить вас в правильном направлении. Я вижу, что вы используете ваниль JavaScript, которая может усложнить ситуацию. Но так как вы также используете Laravel и Laravel корабли с поддержкой Vue (по крайней мере, раньше), я покажу вам мою реализацию с использованием Vue. Если вы знаете JavaScript, это не должно быть так сложно понять, так как Vue очень просто.
Хитрость с многофайловой загрузкой заключается в использовании другого массива для хранения ваших файлов как нативного FileList
объект, возвращаемый входным файлом, является неизменным. Посмотрите на фрагменты кода ниже (я попытался добавить комментарии, чтобы объяснить, что я делаю.)
Вы можете увидеть рабочий пример в этом ручке .
<!-- @change is the Vue equivalent of onchange -->
<input @change="handleFileSelect" type="file" multiple>
<ul>
<li v-for="(photo, index) in photos" :key="`thumb-${index}`">
<img :src="photo.preview" :alt="photo.file.name">
<button @click="removePhoto(index)" type="button">Remove Photo</button>
</li>
</ul>
В разделе HTML все, что нам нужно сделать, это прослушать изменения в файле и установить место, где мы можем отображать миниатюры для выбранных изображений. Vue делает это очень легко, используя директиву v-for
для перебора массива. Текущий элемент в итерации доступен для li
и его дочерних элементов, и мы можем использовать его для заполнения таких атрибутов, как img
'src
.
export default {
data() {
return {
photos: []
}
},
methods: {
handleFileSelect(e) {
Array.from(e.target.files).forEach(file => {
// perform check here such as making sure its an image
const reader = new FileReader()
reader.onload = () => {
// push the preview result and also the file to photos array
this.photos.push({
preview: reader.result,
file
})
}
reader.readAsDataURL(file)
})
},
removePhoto(index) {
this.photos.splice(index, 1)
},
upload() {
const fd = new FormData()
this.photos.forEach((photo, index) => {
// we only want to append the actual file, excluding the preview
// so we only append the `file` attribute
fd.append(`photo-${index}`, photo.file)
})
// send the data
// for example, using axios
const uploadEndpoint = ''
axios.post(uploadEndpoint, fd, {
headers: {
'Content-Type': 'multipart/form-data' // important
}
})
}
}
}
JavaScript часть довольно проста. Здесь мы создаем photos
«местный штат» для хранения наших фотографий. Мы используем эту переменную для перебора и отображения миниатюр в нашем HTML. Когда пользователь выбирает изображения, мы берем файлы и генерируем для них миниатюру, используя объект FileReader
и помещая его в переменную photos
вместе с реальным файлом.
{
preview: 'data:image/....', // the file preview generated by the FileReader
file: File object // the actual file the user selected
}
Когда пользователь хочет отменить выбор изображения, мы просто splice
его из массива photos
, поэтому массив photos
всегда будет содержать фотографии, которые пользователь хочет загрузить. Когда мы подходим к загрузке, если мы используем AJAX для отправки запроса, мы можем просто создать объект FormData
и добавить к нему каждую фотографию, перебирая переменную photos
. В бэкэнде Laravel доступ к этим фотографиям можно получить с помощью request()->file()
. Перед отправкой запроса вы должны установить правильные заголовки, в основном Content-Type: multipart/form-data
.
. Надеюсь, это дало вам общее представление о том, как решить эту проблему. Если у вас есть какие-либо вопросы, не стесняйтесь оставлять их в разделе комментариев, и я сделаю все возможное, чтобы объяснить больше.
ОБНОВЛЕНИЕ : Подробнее о работе с фотографиями на ваш Laravel Backend
Как только вы успешно отправите запрос от внешнего интерфейса, вы можете получить доступ к фотографиям / файлам с помощью вспомогательной функции Laravel request()->file()
. Это вернет все файлы в запросе в массиве.
dd(request()->file());
Вывод будет выглядеть примерно так:
array:3 [
"photo-0" => Illuminate\Http\UploadedFile {#221
-test: false
-originalName: "The Dark Reef Fugitive.jpg"
-mimeType: "image/jpeg"
-error: 0
#hashName: null
path: "/tmp"
filename: "phpjr6Cx5"
basename: "phpjr6Cx5"
pathname: "/tmp/phpjr6Cx5"
extension: ""
realPath: "/tmp/phpjr6Cx5"
aTime: 2020-03-03 08:29:19
mTime: 2020-03-03 08:29:19
cTime: 2020-03-03 08:29:19
inode: 12976169
size: 298634
perms: 0100600
owner: 1000
group: 1000
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
"photo-1" => Illuminate\Http\UploadedFile {#243
-test: false
-originalName: "Nevermore.jpg"
-mimeType: "image/jpeg"
-error: 0
#hashName: null
path: "/tmp"
filename: "php3LNGW5"
basename: "php3LNGW5"
pathname: "/tmp/php3LNGW5"
extension: ""
realPath: "/tmp/php3LNGW5"
aTime: 2020-03-03 08:29:19
mTime: 2020-03-03 08:29:19
cTime: 2020-03-03 08:29:19
inode: 12976170
size: 322173
perms: 0100600
owner: 1000
group: 1000
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
"photo-2" => Illuminate\Http\UploadedFile {#250
-test: false
-originalName: "Magnanumus.png"
-mimeType: "image/png"
-error: 0
#hashName: null
path: "/tmp"
filename: "phpJZ9El6"
basename: "phpJZ9El6"
pathname: "/tmp/phpJZ9El6"
extension: ""
realPath: "/tmp/phpJZ9El6"
aTime: 2020-03-03 08:29:19
mTime: 2020-03-03 08:29:19
cTime: 2020-03-03 08:29:19
inode: 12976172
size: 1068594
perms: 0100600
owner: 1000
group: 1000
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
]
Как видите, каждый файл является экземпляром Illuminate\Http\UploadedFile
, Чтобы сохранить этот файл, у вас есть несколько вариантов. Один из них - использовать функцию store
или storeAs
для файла или просто использовать метод Storage
фасад put
или putFileAs
. Вот пример:
$filePaths = collect(request()->file())->values()->map(function ($photo) {
return Storage::put('photos', $photo);
// OR
// return Storage::putFileAs('photos', $photo, $photo->getClientOriginalName());
// OR
// return $photo->store('photos');
// OR
// return $photo->storeAs('photos', $photo->getClientOriginalName());
});
Прочитайте документацию Laravel в файловом хранилище , чтобы понять другие параметры.
$filePaths
будет массивом путей, где фотографии были сохранены.