こんにちは、かつコーチです。
今回は、LaravelのVuejs + Inertiaを使った画像のアップロード方法についてです。
コード全体
Index.vueで一覧画面と登録画面を一緒にしています。
<script setup>
import { ref } from "vue";
import { Head, useForm } from "@inertiajs/vue3";
// Layouts
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue";
// Components
import InputError from "@/Components/InputError.vue";
import PrimaryButton from "@/Components/PrimaryButton.vue";
defineProps({
images: {
type: Array,
required: true,
},
});
const form = useForm({
image: null,
});
const previewImage = ref(null);
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
previewImage.value = URL.createObjectURL(file);
form.image = file;
} else {
previewImage.value = null;
form.image = null;
}
};
const uploadImage = () => {
form.post(route('image.store'), {
onSuccess: () => {
form.reset('image');
previewImage.value = null;
},
});
};
</script>
<template>
<Head title="Profile" />
<AuthenticatedLayout>
<template #header>
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">Image</h2>
</div>
</template>
<div class="flex gap-5 p-6">
<!-- 画像一覧 -->
<div class="flex flex-col">
<h3>画像一覧</h3>
<div v-if="images.length" class="grid grid-cols-4 gap-5">
<div v-for="image in images" :key="image.id" class="border rounded">
<img
:src="`/storage/images/${image.path}`"
alt="Uploaded Image"
class="w-full h-40 object-cover"
/>
</div>
</div>
<div v-else>
<p>画像がありません</p>
</div>
</div>
<div class="w-80 flex flex-col">
<h2>作成</h2>
<form @submit.prevent="uploadImage">
<div class="mb-4">
<label
for="image"
class="block text-sm font-medium text-gray-700"
@change="form.image = $event.target.files[0]"
>Image</label
>
<input
type="file"
name="image"
id="image"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
@change="handleFileChange"
/>
<InputError :message="form.errors.password" class="mt-2" />
</div>
<div v-if="previewImage" class="mb-4">
<h3>プレビュー画面</h3>
<img :src="previewImage"
alt="Preview Image"
class="w-full h-40 object-cover"
/>
</div>
<PrimaryButton type="submit" :disabled="form.processing"
>登録</PrimaryButton
>
</form>
</div>
</div>
</AuthenticatedLayout>
</template>
一覧画面の部分
<div class="flex flex-col">
<h3>画像一覧</h3>
<div v-if="images.length" class="grid grid-cols-4 gap-5">
<div v-for="image in images" :key="image.id" class="border rounded">
<img
:src="`/storage/images/${image.path}`"
alt="Uploaded Image"
class="w-full h-40 object-cover"
/>
</div>
</div>
<div v-else>
<p>画像がありません</p>
</div>
</div>
画像があれば表示し、ない場合は「画像がありません。」と表示します。
登録画面の部分
<div class="w-80 flex flex-col">
<h2>登録</h2>
<form @submit.prevent="uploadImage">
<div class="mb-4">
<label
for="image"
class="block text-sm font-medium text-gray-700"
@change="form.image = $event.target.files[0]"
>Image</label
>
<input
type="file"
name="image"
id="image"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
@change="handleFileChange"
/>
<InputError :message="form.errors.password" class="mt-2" />
</div>
<div v-if="previewImage" class="mb-4">
<h3>プレビュー画面</h3>
<img :src="previewImage"
alt="Preview Image"
class="w-full h-40 object-cover"
/>
</div>
<PrimaryButton type="submit" :disabled="form.processing"
>登録</PrimaryButton
>
</form>
</div>
次に、Script部分です。
import { ref } from "vue";
import { Head, useForm } from "@inertiajs/vue3";
// Layouts
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue";
// Components
import InputError from "@/Components/InputError.vue";
import PrimaryButton from "@/Components/PrimaryButton.vue";
defineProps({
images: {
type: Array,
required: true,
},
});
const form = useForm({
image: null,
});
const previewImage = ref(null);
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
previewImage.value = URL.createObjectURL(file);
form.image = file;
} else {
previewImage.value = null;
form.image = null;
}
};
const uploadImage = () => {
form.post(route('image.store'), {
onSuccess: () => {
form.reset('image');
previewImage.value = null;
},
});
};
コントローラーは次の通りです。
public function store(StoreImageRequest $request)
{
$request->validated();
$file = $request->file('image');
$filename = $file->hashName();
$path = $file->storeAs('images', $filename, 'public');
$filename = basename($path);
try {
DB::transaction(function () use ($filename) {
Image::create([
'path' => $filename,
]);
});
return to_route('images.index')->with('success', 'Image uploaded successfully.');
} catch (\Throwable $e) {
Log::error($e->getMessage());
return redirect()->back()->with('error', 'An error occurred while uploading the image.');
}
}