文章轉發自專業的Laravel開發者社區,原始連接:learnku.com/laravel/t/3…php
咱們在第三部分中放棄構建真實的用戶端,而學習使用 Vue 路由獲取組件數據的新方式。如今咱們準備將注意力轉移到爲用戶建立 CRUD(增刪改查)的功能上 —— 本教程將聚焦在編輯已存在的用戶。css
在處理第一個表單時,咱們有機會了解如何定義動態 Vue 路由。咱們的路由的動態部分是與用戶數據記錄匹配的用戶 ID。對於編輯用戶,Vue 路由以下所示:前端
/users/:id/edit
複製代碼
這個路由的動態部分是 :id
參數,它將取決於用戶的 ID。咱們將使用數據庫中的 id
字段,但你也可使用 UUID 或者其餘的數據標識。vue
在處理 Vue
組件以前,咱們須要定一個新的 API
接口來獲取指定的用戶,而後再定義一個接口來處理更新。ios
打開 routes/api.php
路由文件,在獲取所有用戶的 index
路由下方添加下面的路由:laravel
Route::namespace('Api')->group(function () {
Route::get('/users', 'UsersController@index');
Route::get('/users/{user}', 'UsersController@show');
});
複製代碼
理由 Laravel 內置的路由模型綁定,控制器方法將很簡單明瞭。在 app/Http/Controllers/Api/UsersController.php
中添加下面的方法:數據庫
// app/Http/Controllers/Api/UsersController
public function show(User $user)
{
return new UserResource($user);
}
複製代碼
像 /api/users/1
這樣請求一個用戶,將返回以下的 JSON
:編程
{
"data": {
"name": "Antonetta Zemlak",
"email":"znikolaus@example.org"
}
}
複製代碼
第三部分的 UserResource
須要包含 id
列,因此須要更新 app/Http/Resources/UserResource.php
添加 id
鍵。整個文件以下:axios
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class UserResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
];
}
}
複製代碼
如今 /api/users
和 /api/users/{user}
路由都將返回 id
字段,經過這個,能夠在路由中區分用戶。後端
定義了 show
以後,咱們接着定義 Vue 中的路由和相應的組件。新增相應的路由到 resources/js/app.js
中。下面是引入 UsersEdit
組件(還沒有建立)和整個路由實例的代碼片斷:
import UsersEdit from './views/UsersEdit';
// ...
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/hello',
name: 'hello',
component: Hello,
},
{
path: '/users',
name: 'users.index',
component: UsersIndex,
},
{
path: '/users/:id/edit',
name: 'users.edit',
component: UsersEdit,
},
],
});
複製代碼
咱們在 routes
末尾新增了 users.edit
路由。
下一步, 咱們須要在 resources/assets/js/views/UsersEdit.vue
中建立 UsersEdit
組件。代碼以下:
<template>
<div>
<form @submit.prevent="onSubmit($event)">
<div class="form-group">
<label for="user_name">Name</label>
<input id="user_name" v-model="user.name" />
</div>
<div class="form-group">
<label for="user_email">Email</label>
<input id="user_email" type="email" v-model="user.email" />
</div>
<div class="form-group">
<button type="submit">Update</button>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
user: {
id: null,
name: "",
email: ""
}
};
},
methods: {
onSubmit(event) {
// @todo form submit event
}
},
created() {
// @todo load user details
}
};
</script>
複製代碼
首先看下 template 部分:咱們在 div
中書寫 <form>
,由於稍後咱們只須要在加載了 user
數據後展現 <form>
。
<form>
有一個默認的 @submit
事件,咱們定義了一個 onSubmit()
方法去處理它。最後須要提一下在 <input>
元素上的 v-model
屬性,它和 data.users
對象一一對應。咱們爲 id
,name
,和 email
設置了默認值。
如今你打開 /users/1/edit
應該看到一個空白的表單:
:id
,在
UsersEdit.vue
中加載用戶數據。
在咱們在組件中加載用戶數據以前,咱們先定義一個額外的專用模塊去處理 /api/users
的資源,包括查詢全部用戶,查詢單個用戶和更新用戶。
第一步,建立一個新的文件夾來放置請求後端的模塊。你能夠用任意方式來建立這些文件。下面咱們展現了在 Nix
下的命令:
mkdir -p resources/assets/js/api/
touch resources/assets/js/api/users.js
複製代碼
users.js
模塊會暴露一些用來處理 /api/users
資源的方法。這個模塊會盡量的簡單,但以後你能夠在請求以前或者以後隨意處理數據。這個文件用做可複用的API操做的存儲庫:
import axios from 'axios';
export default {
all() {
return axios.get('/api/users');
},
find(id) {
return axios.get(`/api/users/${id}`);
},
update(id, data) {
return axios.put(`/api/users/${id}`, data);
},
};
複製代碼
如今咱們可使用一樣的模塊去獲取全部用戶,查詢和更新單個用戶:
// 獲取全部用戶
client.all().then((data) => mapData);
// 查詢單個用戶
client.find(userId);
複製代碼
目前爲止,all()
方法不支持分頁,須要你本身去實現分頁,而後使用新的 all()
替換 UsersIndex.vue
組件中的方法。
如今咱們有了一個可複用但很簡陋的api客戶端,當編輯頁面生成以後咱們使用它來獲取用戶數據。
最初,咱們在組件中添加了 created()
方法,如今咱們能夠在它裏面獲取用戶的數據:
// UsersEdit.vue Component
<script>
import api from '../api/users';
export default {
// ...
created() {
api.find(this.$route.params.id).then((response) => {
this.loaded = true;
this.user = response.data.data;
});
}
}
</script>
複製代碼
在 created()
中,users.js
客戶端使用 find()
方法返回了一個 Promise 對象。在 Promise 的回調中,咱們設置了 loaded
屬性(還沒有建立)並設置了the user
屬性。
如今往 data
中添加 loaded
屬性,默認值爲 false :
data() {
return {
loaded: false,
user: {
id: null,
name: "",
email: ""
}
};
},
複製代碼
因爲咱們的組件在 created()
中加載數據,因此在組件加載數據時顯示「加載」的提示消息:
<div v-if="! loaded">Loading...</div>
<form @submit.prevent="onSubmit($event)" v-else>
<!-- ... -->
</form>
複製代碼
刷新頁面,你會看到一個簡單的 Loading...
信息:
而後用戶數據會顯示在表單中:
API速度很快,若是你要肯定 loading 提示正常工做,你須要使用 setTimeout
去延遲設置 user
屬性:
api.find(this.$route.params.id).then((response) => {
setTimeout(() => {
this.loaded = true;
this.user = response.data.data;
}, 5000);
});
複製代碼
上面的代碼會顯示 loading 消息5秒,而後設置 loaded
和 user
屬性。
咱們將完成 onSubmit()
方法,並用過 PUT /api/users/{user}
更新用戶。
咱們先完善 onSubmit()
,以後會轉到後端處理數據庫的更新:
onSubmit(event) {
this.saving = true;
api.update(this.user.id, {
name: this.user.name,
email: this.user.email,
}).then((response) => {
this.message = 'User updated';
setTimeout(() => this.message = null, 2000);
this.user = response.data.data;
}).catch(error => {
console.log(error)
}).then(_ => this.saving = false);
},
複製代碼
咱們經過用戶 ID 調用 api.update()
方法,傳入從綁定表單中獲取的 name
和 email
的值。
而後咱們在 Promise 上連接一個回調方法,在 API 成功執行以後設置成功提示信息,並設置最新的用戶數據。2000
毫秒後咱們置空提示信息,這一樣會隱藏模板中的消息。
目前爲止,咱們只是單純的抓取全部錯誤並輸出到控制檯。將來,咱們會回頭重寫錯誤(服務端錯誤或者驗證錯誤)處理,可是如今,咱們略過這一部分,專一在請求成功後的處理。
咱們經過 this.saving
來肯定咱們是否在更新用戶信息。咱們給模板添加了 :disabled
屬性,來避免重複提交,它能保證當咱們在更新數據時提交按鈕是禁止狀態:
<div class="form-group">
<button type="submit" :disabled="saving">Update</button>
</div>
複製代碼
咱們在 catch
以後另外連接了一個 then()
,一旦 API 請求結束,就將 this.saving
設爲 false
。咱們須要重置這個屬性爲 false
,來確保咱們能夠再次提交數據。咱們最後的 then()
使用了 _
來表示這裏有一個變量,但咱們並不須要使用。你也能夠定義一個使用空括號的箭頭函數:
.then(() => this.saving = false);
複製代碼
咱們在 data()
中新添了了兩個屬性:
data() {
return {
message: null,
loaded: false,
saving: false,
user: {
id: null,
name: "",
email: ""
}
};
},
複製代碼
下一步,咱們來修改 <template>
來展現 message
:
<template>
<div>
<div v-if="message" class="alert">{{ message }}</div>
<div v-if="! loaded">Loading...</div>
<form @submit.prevent="onSubmit($event)" v-else>
<div class="form-group">
<label for="user_name">Name</label>
<input id="user_name" v-model="user.name" />
</div>
<div class="form-group">
<label for="user_email">Email</label>
<input id="user_email" type="email" v-model="user.email" />
</div>
<div class="form-group">
<button type="submit" :disabled="saving">Update</button>
</div>
</form>
</div>
</template>
複製代碼
最後,咱們在 UsersEdit.vue
文件底部爲 alert
信息添加一些樣式:
<style lang="scss" scoped>
$red: lighten(red, 30%);
$darkRed: darken($red, 50%);
.form-group label {
display: block;
}
.alert {
background: $red;
color: $darkRed;
padding: 1rem;
margin-bottom: 1rem;
width: 50%;
border: 1px solid $darkRed;
border-radius: 5px;
}
</style>
複製代碼
如今,前端組件已經修改完畢,它能夠處理表單的提交,並能在 API 成功執行以後同步更新模板。如今咱們須要轉到後端來完成剩下的部分。
咱們準備在 User
資源控制器上定義一個 update
方法來鏈接全部部分。咱們在服務端進行數據驗證。但咱們暫時不會和前端對接。
第一步,咱們在 routes/api.php
中定義新的路由 PUT /api/users/{user}
:
Route::namespace('Api')->group(function () {
Route::get('/users', 'UsersController@index');
Route::get('/users/{user}', 'UsersController@show');
Route::put('/users/{user}', 'UsersController@update');
});
複製代碼
下一步,UsersController@update
方法會使用 request 對象來驗證數據,並返回咱們要更新的數據。把下面的方法添加到 app/Http/Controllers/Api/UsersController.php
中:
public function update(User $user, Request $request)
{
$data = $request->validate([
'name' => 'required',
'email' => 'required|email',
]);
$user->update($data);
return new UserResource($user);
}
複製代碼
像 show()
方法那樣,咱們使用隱式的模型綁定從數據庫中加載用戶數據。數據驗證後,更新用戶模型,並新建一個 UserResource
,返回更新過的模型。
成功的面向後端的請求會返回更新過的用戶的數據(JSON格式),而後咱們用它更新 Vue 組件中的 this.user
屬性。
{
"data": {
"id": 1,
"name":"Miguel Boyle",
"email":"hirthe.joel@example.org"
}
}
複製代碼
咱們一直在直接請求 /users/:id/edit
頁面, 可是,咱們沒有在界面的任何地方添加路由。 在看到我是如何作到這一點以前,不妨本身嘗試找出如何動態地導航到編輯頁面。
這是我在 第二部分 建立了 UsersIndex.vue
模板,併爲 /users
索引頁上列出了每一個用戶添加編輯連接的方式:
<ul v-if="users">
<li v-for="{ id, name, email } in users">
<strong>Name:</strong> {{ name }},
<strong>Email:</strong> {{ email }} |
<router-link :to="{ name: 'users.edit', params: { id } }">Edit</router-link>
</li>
</ul>
複製代碼
咱們從新構造循環中的 user
對象,以提供 id
, name
和 email
屬性。咱們使用 <router-link/>
組件來引入咱們的命名的 users.edit
路由,使用 params
傳遞 id
參數。
爲了更好地可視化 <router-link>
屬性,面是咱們以前添加的 app.js
文件中的路由定義:
{
path: '/users/:id/edit',
name: 'users.edit',
component: UsersEdit,
},
複製代碼
若是您刷新應用程序或訪問 /users
端點,您將看到以下內容:
若是你如今想編輯一個用戶,在後臺須要保存它並返回一個200
的狀態碼來表示響應成功。 在 PUT
成功請求以後你應該會在兩秒鐘內看到如下內容:
你能夠在下面看到完整的UsersEdit.vue
組件內容:
<template>
<div>
<div v-if="message" class="alert">{{ message }}</div>
<div v-if="! loaded">Loading...</div>
<form @submit.prevent="onSubmit($event)" v-else>
<div class="form-group">
<label for="user_name">Name</label>
<input id="user_name" v-model="user.name" />
</div>
<div class="form-group">
<label for="user_email">Email</label>
<input id="user_email" type="email" v-model="user.email" />
</div>
<div class="form-group">
<button type="submit" :disabled="saving">Update</button>
</div>
</form>
</div>
</template>
<script>
import api from '../api/users';
export default {
data() {
return {
message: null,
loaded: false,
saving: false,
user: {
id: null,
name: "",
email: ""
}
};
},
methods: {
onSubmit(event) {
this.saving = true;
api.update(this.user.id, {
name: this.user.name,
email: this.user.email,
}).then((response) => {
this.message = 'User updated';
setTimeout(() => this.message = null, 10000);
this.user = response.data.data;
}).catch(error => {
console.log(error)
}).then(_ => this.saving = false);
}
},
created() {
api.find(this.$route.params.id).then((response) => {
setTimeout(() => {
this.loaded = true;
this.user = response.data.data;
}, 5000);
});
}
};
</script>
<style lang="scss" scoped>
$red: lighten(red, 30%);
$darkRed: darken($red, 50%);
.form-group label {
display: block;
}
.alert {
background: $red;
color: $darkRed;
padding: 1rem;
margin-bottom: 1rem;
width: 50%;
border: 1px solid $darkRed;
border-radius: 5px;
}
</style>
複製代碼
用戶信息更新成功後,咱們僅僅只是在兩秒鐘後重置該消息。 修改成已設置消息,並將用戶重定向回先前的位置(如, /users
頁)。
其次,在表單底部添加一個 返回
或 取消
按鈕,以放棄更新,並導航回上一頁。
若是您認爲不嚴謹,請在 UsersEdit
組件向 API 發送無效請求時顯示驗證錯誤。 成功提交表單後,清除錯誤消息。
隨着用戶的更新,咱們將注意力轉移到刪除用戶上。刪除用戶將有助於演示成功刪除後以編程方式進行導航。如今,咱們將定義一個全局404頁面,由於咱們具備用於編輯用戶的動態路由。
若是您準備好了,請繼續第五部分.