手把手帶你使用Vue + Laravel開發一個簡單的 CRUD 應用

2022-04-15 22:00:22
本篇文章給大家分享一個Vue+Laravel開發教學,介紹一下怎麼使用 和 Laravel 共建一個簡單的 CRUD 應用,希望對大家有所幫助!

CURD (增刪改查)是資料儲存的基本操作,也是你作為 Laravel 開發人員首先要學習的內容之一

但是,如果要結合以 Vue.js 作為前端的應用程式該注意哪些問題呢?首先,因為現在的操作不重新整理頁面,所以你需要非同步 CURD 。因此,你需要確保資料在前後端的一致性。(學習視訊分享:)

在本教學中,我會演示如何開發完整的 Laravel&Vue.js 應用程式和每個 CURD 的例子。 AJAX 是連線前後端的關鍵,所以,我會使用 Axios 作為 HTTP 使用者端。我還將向您展示一些處理這種體系結構的使用者體驗方面缺陷的方法。

你可以在 GitHub 中檢視完整的專案。

https://github.com/anthonygore/vue-laravel-crud

演示 app

這是一個讓使用者建立一個 「Cruds「 的全棧應用,當我進入這個應用時,它會創造很多不可思議的東西。外星人獨特的名稱和可以在紅色,綠色和黑色的自由轉換。

Cruds 應用展示在主頁,你可以通過 add 按鈕新增 Cruds , delete 按鈕刪除它們,或者更新它們的顏色。

file

Laravel 後端的 CRUD

我們將使用 Laravel 後端開始本教學,來完成 CRUD 操作。我將保持這一部分簡短,因為 Laravel 的 CRUD 是其他地方廣泛涉及的主題.

總之,我們完成以下操作

  • 設定資料庫
  • 通過資源控制器來編寫一個 RESTful API 的路由
  • 在控制器中定義方法,來完成 CRUD 操作

Database

首先是遷移,我們的 Cruds 有兩個屬性:名稱和顏色,我們將其設定為 text 型別

2018_02_02_081739_create_cruds_table.php

<?php

...

class CreateCrudsTable extends Migration
{
  public function up()
  {
    Schema::create('cruds', function (Blueprint $table) {
      $table->increments('id');
      $table->text('name');
      $table->text('color');
      $table->timestamps();
    });
  }

  ...
}
...

API

現在我們來設定 RESTful API 路由. 這個 resource 方法將自動建立我們所需要的所有操作. 但是, 我們不需要 edit, showstore 這幾個路由,因此我們需要排除它們.

routes/api.php

<?php

Route::resource('/cruds', 'CrudsController', [
  'except' => ['edit', 'show', 'store']
]);

有了這些, 我們現在可以在API中使用以下路由:

HTTP 方法地址方法路由名
GET/api/crudsindexcruds.index
GET/api/cruds/createcreatecruds.create
PUT/api/cruds/{id}updatecruds.update
DELETE/api/cruds/{id}destroycruds.destroy

控制器

我們現在需要在控制器中實現這些操作:

app/Http/Controllers/CrudsController.php

<?php

namespace App\Http\Controllers;

use App\Crud;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Faker\Generator;

class CrudsController extends Controller
{
  // Methods
}

我們先簡要概述下每種方法:

create 方法。我們使用 Laravel 附帶的 Faker 包,為 Crud 隨機生成名稱和顏色欄位 。隨後,我們將新生成的資料作為 JSON 返回。

<?php

...

public function create(Generator $faker)
{
  $crud = new Crud();
  $crud->name = $faker->lexify('????????');
  $crud->color = $faker->boolean ? 'red' : 'green';
  $crud->save();

  return response($crud->jsonSerialize(), Response::HTTP_CREATED);
}

index方法。我們使用 index 方法返回 Cruds 的全部資料。在一個更嚴肅的應用中,我們會使用分頁,但是現在我們儘量保持簡潔。

<?php

...

public function index()
{
  return response(Crud::all()->jsonSerialize(), Response::HTTP_OK);
}

update。此方法允許使用者端更改 Crud 的顏色。

<?php

...

public function update(Request $request, $id)
{
  $crud = Crud::findOrFail($id);
  $crud->color = $request->color;
  $crud->save();

  return response(null, Response::HTTP_OK);
}

destroy。 刪除 Cruds 的方法。

<?php

...

public function destroy($id)
{
  Crud::destroy($id);

  return response(null, Response::HTTP_OK);
}

Vue.js 應用

現在開始處理 Vue 頁面展示部分。先來建立一個元件 --- CrudComponent.vue,用來展示 Cruds 的內容。

file

這個元件主要是展示的功能,沒有太多的業務邏輯。主要有以下幾個重點:

  • 展示一張圖片,圖片的顏色取決於 Crud 的顏色( 也就是展示 red.png 還是 green.png)
  • 有一個刪除按鈕,當點選時會觸發 del 方法,繼而觸發一個 delete 事件,並攜帶當前 Crud 的 ID 作為引數
  • 有一個 HTML 選擇器 ( 用來選擇顏色 ),當發生選擇時,會觸發 update 方法,繼而觸發一個 update 事件,並攜帶當前 Crud 的 ID 和新選擇的顏色作為引數

resources/assets/js/components/CrudComponent.vue

<template>
  <p class="crud">
    <p class="col-1">
      <img :src="image"/>
    </p>
    <p class="col-2">
      <h3>Name: {{ name | properCase }}</h3>
      <select @change="update">
        <option
          v-for="col in [ 'red', 'green' ]"
          :value="col"
          :key="col"
          :selected="col === color ? 'selected' : ''"
        >{{ col | properCase }}</option>
      </select>
      <button @click="del">Delete</button>
    </p>
  </p>
</template>
<script>
  export default {
    computed: {
      image() {
        return `/images/${this.color}.png`;
      }
    },
    methods: {
      update(val) {
        this.$emit('update', this.id, val.target.selectedOptions[0].value);
      },
      del() {
        this.$emit('delete', this.id);
      }
    },
    props: ['id', 'color', 'name'],
    filters: {
      properCase(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
      }
    }
  }
</script>
<style>...</style>

在這個專案中還有一個元件 App.vue。它在整個專案中的地位非常重要,所有主要的邏輯都寫在這裡。下面就來逐步分析這個檔案。

先從 template 標籤開始, 它主要處理了下面這些業務:

  • 為我們上面提到的 crud-component 元件佔位
  • 遍歷包含 Crud 物件的陣列(也就是 cruds 陣列 ),陣列中的每個元素都對應著一個 crud-component 元件。我們以 props 的形式把每個 Crud 的屬性傳遞給這個元件,並且監聽來自這個元件的 updatedelete 事件
  • 設定一個 Add 按鈕,當點選時,會觸發 create 方法,從而建立新的 Cruds

resources/assets/js/components/App.vue

<template>
  <p id="app">
    <p class="heading">
      <h1>Cruds</h1>
    </p>
    <crud-component
      v-for="crud in cruds"
      v-bind="crud"
      :key="crud.id"
      @update="update"
      @delete="del"
    ></crud-component>
    <p>
      <button @click="create()">Add</button>
    </p>
  </p>
</template>

下面來看 App.js 檔案的 script 部分:

  • 首先通過 Crud 函數建立用於展示 Cruds 的物件, 包括 ID, 顏色和姓名
  • 然後, 引入 CrudComponent 元件
  • 元件的 cruds 陣列作為 data 的屬性。 關於對 CRUD 的增刪改查的具體操作, 會在下一步展開說明。

resources/assets/js/components/App.vue

<template>...</template>
<script>
  function Crud({ id, color, name}) {
    this.id = id;
    this.color = color;
    this.name = name;
  }

  import CrudComponent from './CrudComponent.vue';

  export default {
    data() {
      return {
        cruds: []
      }
    },
    methods: {
      create() {
        // 待完善
      },
      read() {
        // 待完善
      },
      update(id, color) {
        // 待完善
      },
      del(id) {
        // 待完善
      }
    },
    components: {
      CrudComponent
    }
  }
</script>

前端通過 AJAX 觸發 CURD

在一個完整的專案中,所有的 CRUD 操作都是在後端完成的,因為資料庫是跟後端互動的。然而,觸發 CRUD 的操作幾乎都是在前端完成的。

因此,一個 HTTP 使用者端(也就是負責在前後端之間互動資料的橋樑)的作用是非常重要的。被 Laravel 前端預設封裝的 Axios, 就是一個非常好用的 HTTP 使用者端。

再來看下資源表,每個 AJAX 請求都需要有一個明確的 API 介面:

VerbPathActionRoute Name
GET/api/crudsindexcruds.index
GET/api/cruds/createcreatecruds.create
PUT/api/cruds/{id}updatecruds.update
DELETE/api/cruds/{id}destroycruds.destroy

Read

首先來看 read 方法。這個方法是負責在前端發起 Cruds 請求的,對應後端的處理在是控制器裡的 index 方法,因此使用 GET 請求 /api/cruds

由於 Laravel 前端預設把 Axios 設定為 window 的一個屬性, 因此我們可以使用 window.axios.get 來發起一個 GET 請求。

對於像 get, post 等 Axios 方法的返回結果,我們可以再繼續鏈式呼叫 then 方法,在 then 方法裡可以獲取到 AJAX 響應資料的主體 data 屬性。

resources/assets/js/components/App.vue

...

methods() {
  read() {
    window.axios.get('/api/cruds').then(({ data }) => {
      // console.log(data)
    });
  },
  ...
}

/*
Sample response:

[
  {
    "id": 0,
    "name": "ijjpfodc",
    "color": "green",
    "created_at": "2018-02-02 09:15:24",
    "updated_at": "2018-02-02 09:24:12"
  },
  {
    "id": 1,
    "name": "wjwxecrf",
    "color": "red",
    "created_at": "2018-02-03 09:26:31",
    "updated_at": "2018-02-03 09:26:31"
  }
]
*/

從上面的返回結果可以看出,返回的結果是 JSON 陣列。Axios 會自動將其解析並轉成 JavaScript 物件返給我們。這樣方便我們在回撥函數裡對結果進行遍歷,並通過 Crud 工廠方法建立新的 Cruds,並存到 data 屬性的 cruds 陣列中,例如 this.cruds.push(...)

resources/assets/js/components/App.vue

...

methods() {
  read() {
    window.axios.get('/api/cruds').then(({ data }) => {
      data.forEach(crud => {
        this.cruds.push(new Crud(crud));
      });
    });
  },
},
...
created() {
  this.read();
}

注意:我們通過 created 方法,可以使程式在剛一載入時就觸發 read 方法,但這並非最佳實踐。最好方案應該是直接去掉 read 方法,當程式第一次載入的時候,就把應用的初始狀態都包含在檔案投中。

通過上面的步驟,我們就能看到 Cruds 展示在介面上了:

file

更新 (以及狀態同步)

執行 update 方法需要傳送表單資料,比如 color,這樣控制器才知道要更新哪些資料。Crud 的 ID 是從伺服器端獲取的。

還記得我在本文開篇就提到關於前後端資料一致的問題,這裡就是一個很好的例子。

當需要執行 update 方法時,我們可以不用等待伺服器返回結果,就在前端更新 Crud 物件,因為我們很清楚更新後應該是什麼狀態。

但是,我們不應該這麼做。為什麼?因為有很多原因可能會導致更新資料的請求失敗,比如網路突然中斷,或者更新的值被資料庫拒絕等。

所以等待伺服器返回更新成功的資訊後,再重新整理前端的狀態是非常重要的,這樣我們才能確保前後端資料的一致。

resources/assets/js/components/App.vue

methods: {
  read() {
    ...
  },
  update(id, color) {
    window.axios.put(`/api/cruds/${id}`, { color }).then(() => {
      // 一旦請求成功,就更新 Crud 的顏色
      this.cruds.find(crud => crud.id === id).color = color;
    });
  },
  ...
}

你可能會說這樣非必要的等待會影響使用者體驗,但是我想說,我們在不確定的情況下更新狀態,誤導使用者,這應該會造成更差的使用者體驗。

建立和刪除

現在你已經明白整個架構的關鍵點了,剩下兩個方法,不需要我解釋,你也應該能夠理解其中的邏輯了:

resources/assets/js/components/App.vue

methods: {
  read() {
    ...
  },
  update(id, color) {
    ...
  },
  create() {
    window.axios.get('/api/cruds/create').then(({ data }) => {
      this.cruds.push(new Crud(data));
    });
  },
  del(id) {
    window.axios.delete(`/api/cruds/${id}`).then(() => {
      let index = this.cruds.findIndex(crud => crud.id === id);
      this.cruds.splice(index, 1);
    });
  }
}

載入介面 和 禁止互動


你應該知道,我們這個專案VUE前端的CRUD操作都是非同步方式的,所以前端AJAX請求伺服器並等待伺服器響應返回響應,總會有一點延遲。因為使用者不知道網站在做什麼,此空檔期使用者的體驗不是很好,這學問關聯到UX。

為了改善這UX問題,因此最好新增上一些載入介面並在等待當前操作解決時禁用任何互動。這可以讓使用者知道網站在做了什麼,而且可以確保資料的狀態。

Vuejs有很多很好的外掛能完成這個功能,但是在此為了讓學者更好的理解,做一些簡單的快速的邏輯來完成這個功能,我將建立一個半透明的p,在AJAX操作過程中覆蓋整個螢幕,這個邏輯能完成兩個功能:載入介面和禁止互動。一石兩鳥,完美~

resources/views/index.blade.php

<body>
<p id="mute"></p>
<p id="app"></p>
<script src="js/app.js"></script>
</body>

當進行 AJAX 請求的時候,就把 mute 的值從 false 改為 true, 通過這個值的變化,控制半透明 p 的顯示或隱藏。

resources/assets/js/components/App.vue

export default {
  data() {
    return {
      cruds: [],
      mute: false
    }
  },
  ...
}

下面就是在 update 方法中切換 mute 值的過程。當執行 update 方法時,mute 值被設為 true。當請求成功,再把 mute 值設為 false, 這樣使用者就可以繼續操作應用了。

resources/assets/js/components/App.vue

update(id, color) {
  this.mute = true;
  window.axios.put(`/api/cruds/${id}`, { color }).then(() => {
    this.cruds.find(crud => crud.id === id).color = color;
    this.mute = false;
  });
},

在 CRUDE 的每個方法裡都要有這樣的操作,在此,為了節約篇幅,我就不一一寫明瞭。

為了保證大家不會忘記這個重要的操作,我們直接在 <p id="app"></p> 元素上方增加了 <p id="mute"></p> 元素。

從下面的程式碼可以看到,當 <p id="mute"> 元素被加上 class on 後,它將以灰色調完全覆蓋整個應用,並阻止所有的點選事件:

resources/views/index.blade.php

<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>Cruds</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;,
      height: 100%;
      width: 100%;
      background-color: #d1d1d1
    }
    #mute {
      position: absolute;
    }
    #mute.on {
      opacity: 0.7;
      z-index: 1000;
      background: white;
      height: 100%;
      width: 100%;
    }
  </style>
</head>
<body>
<p id="mute"></p>
<p id="app"></p>
<script src="js/app.js"></script>
</body>
</html>

最後一個問題是對於 on class 的管理,我們可以在 mute 的值上加一個 watch,每當 mute 的值發生改變的時候,就加上或刪除 on class:

export default {
  ...
  watch: {
    mute(val) {
      document.getElementById('mute').className = val ? "on" : "";
    }
  }
}

完成上面所有的步驟,你就可以擁有一個帶有載入指示器的全棧Vue / Laravel CRUD 的應用程式了。再來看下完整效果吧:

file

你可以從 GitHub 獲取程式碼,如果有任何問題或者想法,歡迎給我留言!

英文原文地址:https://vuejsdevelopers.com/2018/02/05/vue-laravel-crud/

譯文地址:https://learnku.com/vuejs/t/24724

(學習視訊分享:、)

以上就是手把手帶你使用Vue + Laravel開發一個簡單的 CRUD 應用的詳細內容,更多請關注TW511.COM其它相關文章!