内容简介:Vue.js (12) - 實戰 CRUD 使用 Laravel + Vue
Vue.js
我們將從無到有實際寫一個簡單的文章管理應用,整個打造的流程大致如下:
- 設定資料庫:為了示範方便,將使用 SQLite。
- 建立 API Routes:我們會透過 API 對資料庫做請求的動作。
- 建立 Post 頁面:在 Laravel 頁面中放入 Post.vue 元件。
- 建立 Post vue 元件:這裡是和使用者互動的部份,藉由前面建立的 API 來操作資料。
我們開始吧~
設定資料庫
你可以使用其他資料庫管理系統,例如 MySQL,這裡為了示範方便使用 SQLite。
1. 建立資料庫檔案
在專案目錄的database
目錄下,執行:
touch sqlite.db
2. 修改 .env
將資料庫的設定改成以下內容:
DB_CONNECTION=sqlite DB_DATABASE=/絕對路徑/laravel-vue/database/sqlite.db
3. 產生 Post 模型及遷移檔
在專案根目錄下執行:
php artisan make:model Post -m
使用 make:model 模型名稱
建立資料模型, -m
是同時建立資料庫遷移檔。這裡是為了簡化操作,你也可以分開建立。
app/Post.php
及
database/migrations/2017_06_06_073431_create_posts_table.php
兩個檔案。其中的
2017_06_06_073431_
會因建立的時間而不同。
4. 編輯 2017_06_06_073431_create_posts_table.php:
PHPpublic function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title'); // 文章的標題
$table->string('body'); // 文章的內容
$table->timestamps();
});
}
存檔,然後執行:
php artisan migrate
這樣資料庫的表格及欄位就建好了,你可以用指令或 SQLPro for SQLite 軟體來查看資料庫的內容。
建立 API Routes
註:請先啟動內建伺服器 php artisan serve
,確定網站是可以正常運作的。
我們會建立 5 個 API :
-
GET http://127.0.0.1:8000/api/posts
:取得全部文章 -
GET http://127.0.0.1:8000/api/posts/{id}
:取得單一文章 -
POST http://127.0.0.1:8000/api/posts
:建立一篇文章 -
PUT http://127.0.0.1:8000/api/posts/{id}
:更新一篇文章 -
DELETE http://127.0.0.1:8000/api/posts/{id}
:刪除一篇文章
routes/api.php
Laravel 5.4 已經內建 API 機制,所有在 api.php
建立的 routes,網址都會以 api
開頭,像這樣 http://127.0.0.1:8000/api
。
這裡有一點要說明,為了示範單純化,我們這裡建立的 API 全都是未受限制的,也就是任何知道網址的人就能存取,這樣其實很危險。在正規的作法下,必須只接受登入後的存取,可以使用中介軟體來達成:
Route::middleware('auth:api')->get(...略);
這樣中介軟體就會過濾掉未登入的操作,記得在正式的產品中,務必加入驗證機制。
取得全部文章
目前資料庫中是空的,我們先用 Tinker來加入一筆資料:
php artisan tinker
這樣會進入 Tinker 的互動模式。Tinker 可以和你的應用程式做互動,其中包括 Eloquent。
之前用指令產生的Post.php
被放在
app
目錄下,因此完整名稱為
App\Post
,我們用它來列出所有文章:
App\Post::all();
應該會是空陣列,因為我們還沒新增資料。動手來新增一筆吧:
// 以下輸入一行可以按 Enter 執行 $post = new App\Post; $post->title = "這是文章標題"; $post->body = "這是文章內容"; $post->save(); // 到這裡如果回傳 true 表示資料新增成功了 // 再來看一次結果 App\Post::all();應該會看到我們新增的文章。現在開啟
api.php
加入我們的第一個 API Route:
PHPRoute::get('/posts', function() {
return response()->json(App\Post::all(), 200);
});
打開瀏覽器進入
http://127.0.0.1:8000/api/posts
看看是否有收到 JSON 格式的資料。
取得單一文章
接著加入取得單一文章的 API Route:
PHPRoute::get('/posts/{id}', function($id) {
return response()->json(App\Post::find($id), 200);
});
看看
http://127.0.0.1:8000/api/posts/1
應該有資料。這個 Route 之後不會用到,單純示範。
建立一篇文章
註:為了示範單純,這裡都不做任何輸入資料的驗證。
加入一個建立文章的 API Route:
PHPRoute::post('/posts/', function(Request $request) {
$post = new Post;
$post->title = $request->input('title', '沒有標題');
$post->body = $request->input('body', '沒有內文。');
$ok = $post->save();
return response()->json(['ok' => $ok], 200);
});
接收 POST (這裡是指表單傳送的方法) 來新增資料,新增後回傳 ok
的值告知是否成功。
命令列工具,執行:
curl -d "title=第2篇文章&body=第2篇文章的內容" http://127.0.0.1:8000/api/posts
得到回傳結果 {"ok":true}
表示成功了。回到 http://127.0.0.1:8000/api/posts
看看,應該會多出一筆資料。
-d
選項是指將它之後的字串內容以 POST 方法傳送到指定的網址。前面取得文章的動作也可以用 curl 來測試:
curl http://127.0.0.1:8000/api/posts curl http://127.0.0.1:8000/api/posts/1
更新一篇文章
加入一個更新文章的 API Route:
PHPRoute::put('/posts/{id}', function(Request $request, $id) {
$ok = false;
$msg = '';
//
$post = Post::find($id);
if ($post) {
$post->title = $request->input('title', '沒有標題');
$post->body = $request->input('body', '沒有內文。');
$ok = $post->save();
if (!$ok) $msg = '更新失敗!';
} else {
$msg = '找不到文章';
}
return response()->json(['ok' => $ok, 'msg' => $msg], 200);
});
測試更新文章:
curl -X PUT -d "title=第2篇文章修改&body=第2篇文章的內容修改" http://127.0.0.1:8000/api/posts/2
回傳 {"ok":true,"msg":""}
表示成功。你可以試試看更新找不到的 id 是否會回傳錯誤訊息。回到 http://127.0.0.1:8000/api/posts
看看結果。
-X
選項可以讓你自定傳送的方法名稱,其他選項和 POST 相同,但是注意網址要附上文章 id。
刪除一篇文章
PHPRoute::delete('/posts/{id}', function($id){
$rows = Post::destroy($id);
$ok = ($rows > 0);
return response()->json(['ok' => $ok], 200);
});
測試:
curl -X DELETE http://127.0.0.1:8000/api/posts/2回傳結果
{"ok":true}
表示成功了。回到
http://127.0.0.1:8000/api/posts
看看結果。
PostController.php
前面我們將 API 的執行工作全都寫在 api.php
中,當功能變多時,夾雜大量的處理邏輯將會變得很混亂,以下將重構處理邏輯,將它們移到相對應的 Controller 中。
執行以下指令:
php artisan make:controller PostController會建立
app/Http/Controllers/PostController.php
,然後將我們在
api.php
中建立的處理邏輯移過來:
PHP<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class PostController extends Controller
{
// API
/**
* 取得全部文章
*/
function apiAll() {
return response()->json(Post::all(), 200);
}
/**
* 取得單一文章
*/
function apiFindPostById($id) {
return response()->json(Post::find($id), 200);
}
/**
* 建立一篇文章
*/
function apiCreatePost(Request $request) {
$post = new Post;
$post->title = $request->input('title', '沒有標題');
$post->body = $request->input('body', '沒有內文。');
$ok = $post->save();
return response()->json(['ok' => $ok], 200);
}
/**
* 更新一篇文章
*/
function apiUpdatePostById(Request $request, $id) {
$ok = false;
$msg = '';
//
$post = Post::find($id);
if ($post) {
$post->title = $request->input('title', '沒有標題');
$post->body = $request->input('body', '沒有內文。');
$ok = $post->save();
if (!$ok) $msg = '更新失敗!';
} else {
$msg = '找不到文章';
}
return response()->json(['ok' => $ok, 'msg' => $msg], 200);
}
/**
* 刪除一篇文章
*/
function apiDeletePostById($id) {
$rows = Post::destroy($id);
$ok = ($rows > 0);
return response()->json(['ok' => $ok], 200);
}
}
接著修改
api.php
,改為使用 PostController:
PHPRoute::get('/posts', 'PostController@apiAll');
Route::get('/posts/{id}', 'PostController@apiFindPostById');
Route::post('/posts', 'PostController@apiCreatePost');
Route::put('/posts/{id}', 'PostController@apiUpdatePostById');
Route::delete('/posts/{id}', 'PostController@apiDeletePostById');
這樣是不是清爽多了~
建立 Post 頁面
API 都打造完成之後,接下來就要讓使用者可以使用它們來操作內容。
routes/web.php
在這裡建立的 Route 是可以讓使用者連入的網址,我們一樣將處理邏輯分開:
PHPRoute::get('/posts', 'PostController@index');
然後在 PostController.php
加上一個新方法:
PHP/**
* 文章首頁
*/
function index()
{
return view('post');
}
// API
...略
非常簡單的只回傳一個 view。
新增 resources/views/layouts/post.blade.php
我們會用到 前一篇建立的 Layout ,所以內容如下:
@extends('layouts.default') @section('title', 'Make CRUD App By Laravel with Vue') @section('content') <Post></Post> @endsection @section('script') <script src="/js/post.js"></script> @endsection
關於 CSS
之前的 Layout 檔沒有用到 CSS,現在來補加,首先編輯webpack.mix.js
:
JavaScriptmix.js('resources/assets/js/hello.js', 'public/js')
.extract(['lodash','jquery','axios','vue'])
.sass('resources/assets/sass/app.scss', 'public/css');
加上 sass
的部分,這是 Laravel 內建的,可以調整成自己想要的。再來是把打包後的 app.css
加入 Layout 中。
resources/views/layouts/default.blade.php
:
HTML...略
<title>@yield('title')</title>
<link rel="stylesheet" href="/css/app.css">
</head>
...略
以上在 Laravel 中關於頁面的部份就完成,接下來終於進入 Vue 的部分了。
建立 Post vue 元件
新增 resources/assets/js/components/Post.vue
HTML<template>
<div class="content">
<div v-for="post in posts">
<h1>{{ post.title }}</h1>
<p>{{ post.body }}</p>
<button class="btn btn-xs btn-primary" @click="modify(post)">修改</button>
<button class="btn btn-xs btn-danger" @click="remove(post.id)">刪除</button>
<hr>
</div>
<form id="form">
<div class="form-group" :class="{ 'has-warning': titleWarning }">
<label class="control-label">標題
<span v-if="titleWarning">不能空白</span>
</label>
<input class="form-control" v-model="post.title">
</div>
<div class="form-group" :class="{ 'has-warning': bodyWarning }">
<label class="control-label">內容
<span v-if="bodyWarning">不能空白</span>
</label>
<textarea class="form-control" v-model="post.body"></textarea>
</div>
<div class="form-group">
<div v-if="isSave">
<button @click.prevent="save">儲存</button>
<button @click.prevent="cancel">取消</button>
</div>
<button v-else @click.prevent="publish">發佈</button>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
posts: [],
post: {
id: null,
title: '',
body: ''
},
titleWarning: false,
bodyWarning: false,
isSave: false
}
},
methods: {
init: function () {
let self = this;
axios.get('/api/posts')
.then(function (response) {
self.posts = response.data;
})
.catch(function (response) {
console.log(response);
});
},
publish: function () {
this.titleWarning = (this.post.title.trim().length == 0);
this.bodyWarning = (this.post.body.trim().length == 0);
if (this.titleWarning || this.bodyWarning) return;
//
let self = this;
axios.post('/api/posts', this.post)
.then(function (response) {
if (response.data['ok']) {
self.init();
self.titleWarning = false;
self.bodyWarning = false;
self.post = {title:'', body:''};
}
})
.catch(function (response) {
console.log(response)
});
},
modify: function (post) {
location.href = "#form";
this.post.id = post.id;
this.post.title = post.title;
this.post.body = post.body;
this.isSave = true;
console.log(this.post);
},
save: function () {
let self = this;
axios.put('/api/posts/' + this.post.id, this.post)
.then(function (response) {
if (response.data['ok']) {
self.init();
self.isSave = false;
self.post = {id:null, title: '', body:''};
}
})
.catch(function (response) {
console.log(response);
});
},
cancel: function () {
this.post = {id: null, title: '', body: ''};
this.isSave = false;
},
remove: function (id) {
let self = this;
axios.delete('/api/posts/' + id)
.then(function (response) {
if (response.data['ok']) {
self.init();
}
})
.catch(function (response) {
console.log(response);
});
}
},
mounted: function () {
this.init();
}
}
</script>
<style scoped>
.content {
padding: 20px;
}
</style>
說明:
- 頁面的排版是上方顯示文章清單,同時附上「修改」與「刪除」的按鈕。
- 接著是一個表單,可同時做為「發佈」新文章及「儲存」修改的內容。
- 在 data() 中,
posts
會儲存全部的文章,post
會和表單的欄位綁定,可做為發佈及修改時的資料。其他 3 個是用來得知狀態改變時用的。 - methods 中,請求都是透過我們建立的 API
- init 用來初始化資料,所以它會去取得全部的文章。
- axios 是一個基於 Promise 的 HTTP 請求套件,由於在其內部中無法使用
this
來存取外部的資料,所以透過let self = this;
轉傳。它是以get().then().catch()
的方式來請求資料,成功時呼叫then()
失敗時呼叫catch()
- publish 會送出新增文章的請求,成功的話執行 init 來取得全部文章。
- modify 會將資料送給
post
,由於它和表單綁定,所以使用者就可以直接在表單上看到內容。 - save 會送出更新文章的請求,成功的話執行 init 來取得全部文章。
- cancel 會取消表單中的內容,並且隱藏「儲存」及「取消」按鈕。
- remove 會送出刪除文章的請求,成功的話執行 init 來取得全部文章。
- mounted 會在網頁載入完成時執行,這裡我們執行 init 方法。
新增 resources/assets/js/post.js
JavaScriptrequire('./bootstrap.js');
import Post from './components/Post.vue';
new Vue({
el: '#app',
components: { Post }
})
webpack.mix.js
JavaScriptmix.js('resources/assets/js/hello.js', 'public/js')
.js('resources/assets/js/post.js', 'public/js')
.extract(['lodash','jquery','axios','vue'])
.sass('resources/assets/sass/app.scss', 'public/css');
把我們新建立的
post.js
加入打包的動作中。
關於 CSRF
Laravel 已經內建 CSRF 保護機制,所以我們必須修改default.blade.php
:
HTML...略
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title')</title>
...略
在 <head>
中加上相關的 meta 值。它被用於 resources/assets/js/bootstrap.js
中,Laravel 已經幫我們指定給 axios 了。如果你少了這個動作,所有表單的送出請求都會被禁止。
好了,全部完成,執行自動打包來看看結果
npm run watch 或 yarn run watch
在瀏覽器中開啟 http://127.0.0.1:8000/posts
試用看看自己打造的應用程式吧~
以上所述就是小编给大家介绍的《Vue.js (12) - 實戰 CRUD 使用 Laravel + Vue》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- RecyclerView使用指南(一)—— 基本使用
- 如何使用Meteorjs使用URL参数
- 使用 defer 还是不使用 defer?
- 使用 Typescript 加强 Vuex 使用体验
- [译] 何时使用 Rust?何时使用 Go?
- UDP协议的正确使用场合(谨慎使用)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。