文章轉發自專業的Laravel開發者社區,原始連接: https://learnku.com/laravel/t...
咱們在第三部分中放棄構建真實的用戶端,而學習使用 Vue 路由獲取組件數據的新方式。如今咱們準備將注意力轉移到爲用戶建立 CRUD(增刪改查)的功能上 —— 本教程將聚焦在編輯已存在的用戶。php
在處理第一個表單時,咱們有機會了解如何定義動態 Vue 路由。咱們的路由的動態部分是與用戶數據記錄匹配的用戶 ID。對於編輯用戶,Vue 路由以下所示:css
/users/:id/edit
這個路由的動態部分是 :id
參數,它將取決於用戶的 ID。咱們將使用數據庫中的 id
字段,但你也可使用 UUID 或者其餘的數據標識。前端
在處理 Vue
組件以前,咱們須要定一個新的 API
接口來獲取指定的用戶,而後再定義一個接口來處理更新。vue
打開 routes/api.php
路由文件,在獲取所有用戶的 index
路由下方添加下面的路由:ios
Route::namespace('Api')->group(function () { Route::get('/users', 'UsersController@index'); Route::get('/users/{user}', 'UsersController@show'); });
理由 Laravel 內置的路由模型綁定,控制器方法將很簡單明瞭。在 app/Http/Controllers/Api/UsersController.php
中添加下面的方法:laravel
// 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
鍵。整個文件以下:編程
<?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
字段,經過這個,能夠在路由中區分用戶。axios
定義了 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頁面,由於咱們具備用於編輯用戶的動態路由。
若是您準備好了,請繼續第五部分.