内容简介: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协议的正确使用场合(谨慎使用)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML Dog
Patrick Griffiths / New Riders Press / 2006-11-22 / USD 49.99
For readers who want to design Web pages that load quickly, are easy to update, accessible to all, work on all browsers and can be quickly adapted to different media, this comprehensive guide represen......一起来看看 《HTML Dog》 这本书的介绍吧!