Berurusan dengan unggahan file di Vue + API adalah pertanyaan yang sulit, dan tidak banyak contoh di luar sana, jadi kami memutuskan untuk memberikan versi kami sendiri, dengan dua proyek demo.
Dalam artikel ini, kami akan memberikan contoh kode dan repositori github di akhir.
Bayangkan sebuah skenario di mana formulir pendaftaran memiliki bidang Avatar.
Beginilah cara kerjanya – tombol register akan membuat permintaan pos ke API dan mengembalikan objek pengguna baru, termasuk Avatar.
Kode front-end: vue.js
Di sisi front-end, itu dilakukan dengan komponen vue Daftar..
Melihat: Dalam artikel ini, saya tidak akan membahas komponen Routing dan Routing Vue Basic Vue. Di akhir artikel, Anda akan melihat tautan ke repositori dengan bagian front-end dan back-end, sehingga Anda akan dapat melihat bagaimana semuanya terkait bersama.
src/views/register.vue: (Lihat Komentar dalam Kode, di Bold + Caps Lock)
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Register</div>
<div class="card-body">
<!-- THIS SECTION IS FOR ERRORS THAT WOULD COME FROM API -->
<div v-if="errors">
<div v-for="error in errors" class="alert alert-danger">{{ error }}</div>
</div>
<!-- FORM WITH v-if WILL BE SHOWN BUT THEN HIDDEN AFTER SUCCESS SUBMIT -->
<form v-if="showForm">
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">Name</label>
<div class="col-md-6">
<!-- NOTICE v-model="formData.name" - THAT'S HOW IT GETS ATTACHED TO THE FIELD -->
<input v-model="formData.name" id="name" type="text" class="form-control" name="name" required autocomplete="name" autofocus>
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">Email</label>
<div class="col-md-6">
<input v-model="formData.email" id="email" type="email" class="form-control" name="email" required autocomplete="email">
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">Password</label>
<div class="col-md-6">
<input v-model="formData.password" id="password" type="password" class="form-control" name="password" required autocomplete="new-password">
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">Confirm password</label>
<div class="col-md-6">
<input v-model="formData.password_confirmation" id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row">
<label class="col-md-4 col-form-label text-md-right">Avatar</label>
<div class="col-md-6">
<div class="custom-file">
<!-- MOST IMPORTANT - SEE "ref" AND "@change" PROPERTIES -->
<input type="file" class="custom-file-input" id="customFile"
ref="file" @change="handleFileObject()">
<label class="custom-file-label text-left" for="customFile">{{ avatarName }}</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button @click.prevent="submit" type="submit" class="btn btn-primary" style="background: #42b983; border: #42b983;">
Register
</button>
</div>
</div>
</form>
<!-- THIS IS THE RESULT BLOCK - SHOWING USER DATA IN CASE OF SUCCESS -->
<div v-if="user">
<div class="alert alert-success">User created</div>
<div>
<img height="100px" width="auto" :src=" alt="">
</div>
<div>Name : {{ user.name }}</div>
<div>Email : {{ user.email }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import _ from 'lodash'
export default {
data() {
return {
formData: {
name: null,
email: null,
password: null,
password_confirmation: null,
},
avatar: null,
avatarName: null,
showForm: true,
user: null,
errors: null,
}
},
methods: {
submit() {
this.errors = null
let formData = new FormData()
<!-- WE APPEND THE AVATAR TO THE FORMDATA WE'RE GONNA POST -->
formData.append('avatar', this.avatar)
_.each(this.formData, (value, key) => {
formData.append(key, value)
})
<!-- THE MOST IMPORTANT - API CALL, WITH multipart/form-data AND boundary HEADERS -->
axios.post('/api/register', formData, {
headers: {
'Content-Type': "multipart/form-data; charset=utf-8; boundary=" + Math.random().toString().substr(2)
}
}
).then(response => {
<!-- HIDING THE FORM AND SHOWING THE USER -->
this.showForm = false
this.user = response.data.data
}).catch(err => {
if (err.response.status === 422) {
<!-- SHOWING THE ERRORS -->
this.errors = []
_.each(err.response.data.errors, error => {
_.each(error, e => {
this.errors.push(e)
})
})
}
});
},
<!-- WHENEVER THE FILE IS CHOSEN - IT'S ATTACHED TO this.avatar BY ref="file" -->
handleFileObject() {
this.avatar = this.$refs.file.files[0]
this.avatarName = this.avatar.name
}
}
}
</script>
Bagian penting lainnya adalah mengatur default untuk Axios – di suatu tempat di SRC/Main.js:
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' axios.defaults.baseURL = ' // Backend URL for API
Oke, jadi sekarang kami memposting formulir ke API. Bagaimana tampilannya di sisi Laravel?
Kode back-end: Laravel
Pendaftaran dilakukan melalui rute ini:
Rute/API.php:
Route::post('/register', 'Api\V1\RegisterController@register');
Dan metode pengontrol adalah ini:
APP/HTTP/Pengontrol/API/V1/Registercontroller.php:
namespace App\Http\Controllers\Api\V1;
use App\Http\Resources\UserResource;
use App\User;
use Illuminate\Http\Request;
class RegisterController
{
public function register(Request $request)
{
$data = $request->validate([
'avatar' => ['image', 'dimensions:max_width=1000,max_height=1000'],
'name' => ['required', 'string'],
'email' => ['required', 'email'],
'password' => ['required', 'confirmed'],
]);
$file = $request->file('avatar');
$name="/avatars/" . uniqid() . '.' . $file->extension();
$file->storePubliclyAs('public', $name);
$data['avatar'] = $name;
$user = User::create($data);
return new UserResource($user);
}
}
Saya telah menebus bagian -bagian yang terkait dengan unggahan avatar. Anda dapat membaca lebih lanjut tentang unggahan file Laravel di halaman dokumentasi resmi ini.
Kami berasumsi itu Users.avatar hanyalah bidang varchar yang berisi jalur ke file, seperti Avatar/some_file_name.jpg:
File itu sendiri akan disimpan di a publik disk, dikonfigurasi config/filesystems.php:
'disks' => [
// ...
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
Hasil pengembalian panggilan API dijelaskan dalam file
APP/HTTP/Resources/userResource.php:
class UserResource extends JsonResource
{
public function toArray($request)
{
return array_merge(parent::toArray($request), [
'avatar_url' => env('APP_URL') . $this->avatar
]);
}
}
Seperti yang Anda lihat, kami mengembalikan URL lengkap avatar ke front-end. Jadi jangan lupa untuk menentukan file app_url Anda di .env.
Jadi, API mengembalikan ini:
{
"data": {
"avatar": "/avatars/5ea54de92ecb4.png",
"name": "Felicia Sims",
"email": "jiquzugiz@yahoo.com",
"updated_at": "2020-04-26 09:01:29",
"created_at": "2020-04-26 09:01:29",
"id": 2,
"avatar_url": "
}
}
Hal terakhir: Untuk membuat semuanya berfungsi, kita juga perlu menambahkan Handlecors kelas di App/http/kernel.php:
use Fruitcake\Cors\HandleCors;
class Kernel extends HttpKernel
{
protected $middleware = [
// ...
HandleCors::class,
];
Dan inilah hasil visual setelah mengisi formulir:

Inilah repositori lengkap untuk proyek ini: https://github.com/laraveldaily/laravel-vue-api-file-upload
Khususnya, komit tentang halaman pendaftaran itu:
Bonus: Contoh Kedua – Menggunakan Space Laravel Medialibrary
Di dalam repositori, Anda akan menemukan kasus lain – mengunggah gambar thumbnail untuk artikel tersebut. Untuk itu, kami menggunakan paket medialibrary spatie.

Kode front-end sangat mirip dalam struktur-inilah src/views/artikel.vue:
<form v-if="showForm">
<!-- ... other fields .. -->
<div class="form-group row">
<label class="col-md-4 col-form-label text-md-right">Thumbnail</label>
<div class="col-md-6">
<div class="custom-file">
<input type="file" class="custom-file-input" id="customFile" ref="file" @change="handleFileObject()">
<label class="custom-file-label text-left" for="customFile">{{ thumbName }}</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button @click.prevent="submit" type="submit" class="btn btn-primary" style="background: #42b983; border: #42b983;">
Create
</button>
</div>
</div>
</form>
<div v-if="article">
<div class="alert alert-success">Article created</div>
<div>
<img height="100px" width="auto" :src=" alt="">
</div>
<div>Title : {{ article.title }}</div>
<div>Content : {{ article.content }}</div>
</div>
<!-- ... -->
<script>
import axios from 'axios'
import _ from 'lodash'
export default {
data() {
return {
formData: {
title: null,
content: null,
},
thumbnail: null,
thumbName: null,
showForm: true,
article: null,
errors: null,
}
},
methods: {
submit() {
this.errors = null
let formData = new FormData()
formData.append('thumbnail', this.thumbnail)
_.each(this.formData, (value, key) => {
formData.append(key, value)
})
axios.post('/api/articles', formData, {
headers: {
'Content-Type': "multipart/form-data; charset=utf-8; boundary=" + Math.random().toString().substr(2)
}
}
).then(response => {
this.showForm = false
this.article = response.data.data
}).catch(err => {
if (err.response.status === 422) {
this.errors = []
_.each(err.response.data.errors, error => {
_.each(error, e => {
this.errors.push(e)
})
})
}
});
},
handleFileObject() {
this.thumbnail = this.$refs.file.files[0]
this.thumbName = this.thumbnail.name
}
}
}
</script>
Back-end menambahkan instalasi default seperti Komposer membutuhkan ruang/laravel-medialibrarydan pengontrol API terlihat seperti ini.
public function store(StoreArticleRequest $request)
{
/** @var Article $article */
$article = Article::create($request->validated());
if ($request->file('thumbnail', false)) {
$article->addMedia($request->file('thumbnail'))->toMediaCollection('thumbnail');
}
$article = $article->fresh();
return new ArticleResource($article);
}
Anda dapat melihat kode lengkap dari versi itu, dalam komitmen repositori ini:
News
Berita
News Flash
Blog
Technology
Sports
Sport
Football
Tips
Finance
Berita Terkini
Berita Terbaru
Berita Kekinian
News
Berita Terkini
Olahraga
Pasang Internet Myrepublic
Jasa Import China
Jasa Import Door to Door
Gaming center adalah sebuah tempat atau fasilitas yang menyediakan berbagai perangkat dan layanan untuk bermain video game, baik di PC, konsol, maupun mesin arcade. Gaming center ini bisa dikunjungi oleh siapa saja yang ingin bermain game secara individu atau bersama teman-teman. Beberapa gaming center juga sering digunakan sebagai lokasi turnamen game atau esports.
Comments are closed, but trackbacks and pingbacks are open.