在這一篇示例教程中,我們將會(huì)構(gòu)建一個(gè)類似 Twitter 的 Web 應(yīng)用。我們將使用到 Laravel 5.6 和 Vue.js,并且在 Vue.js 中定義一些組件,此外,還會(huì)使用 Axios 來(lái)發(fā)送網(wǎng)絡(luò)請(qǐng)求。當(dāng)然,篇幅有限,我們不可能開發(fā)一個(gè)完整的 Twitter 應(yīng)用,而是實(shí)現(xiàn)一個(gè)簡(jiǎn)化版:用戶可以發(fā)送 Tweet 并在自己的時(shí)間線中看到,可以關(guān)注或取消關(guān)注其他用戶,如果關(guān)注了其他用戶,那么也可以看到關(guān)注用戶發(fā)布的 Tweet。麻雀雖小,五臟俱全,希望大家可以通過(guò)這個(gè)簡(jiǎn)單的應(yīng)用學(xué)會(huì) Laravel 和 Vue.js 的基礎(chǔ)用法。
注:這是一篇翻譯文章,你可以將 Twitter 對(duì)標(biāo)國(guó)內(nèi)新浪微博,一條 Tweet 就是一條微博信息。
安裝配置 Laravel
首先,我們需要安裝一個(gè)新的 Laravel 應(yīng)用(也可以通過(guò) Composer 安裝,看個(gè)人喜好):
laravel?new?laratwitter
進(jìn)入該項(xiàng)目根目錄,安裝前端依賴:
npm?install
接下來(lái),修改?.env
?中數(shù)據(jù)庫(kù)相關(guān)配置符合本地環(huán)境,然后通過(guò)如下命令生成用戶認(rèn)證腳手架代碼:
php?artisan?make:auth
運(yùn)行如下命令生成相關(guān)數(shù)據(jù)表:
php?artisan?migrate
接下來(lái)配置下 Web 服務(wù)器(使用 Valet 的話略過(guò)),我這里配置的域名是?laratwitter.test
,配置完成后重啟下 Web 服務(wù)器,然后通過(guò)?http://laratwitter.test/register
?注冊(cè)一個(gè)新用戶:
接下來(lái)編輯?resoureces >> views >> home.blade.php
?文件:
@extends('layouts.app') @section('content') <div?class="container"> ????<div?class="row?justify-content-center"> ????????<div?class="col-md-4"> ????????????Tweet?表單 ????????</div> ????????<div?class="col-md-8"> ???????????時(shí)間線 ????????</div> ????</div> </div> @endsection
新注冊(cè)用戶登錄后就能在新的 Home 頁(yè)看到變更后的效果了。
創(chuàng)建一個(gè) Tweet 表單
我們使用 Vue.js 來(lái)完成表單創(chuàng)建,首先到?resources >> assets >> js >> components
?目錄下新增一個(gè)?FormComponent.vue
?文件:
//?FormComponent.vue <template> ????<div?class="col-md-4"> ????????<form> ????????????<div?class="form-group"> ????????????????<textarea? ????????????????????class="form-control"? ????????????????????rows="8"?cols="8"? ????????????????????maxlength="130"? ????????????????????required> ????????????????</textarea> ????????????</div> ????????????<div?class="form-group"> ????????????????<button?class="btn?btn-primary"> ????????????????????發(fā)送 ????????????????</button> ????????????</div> ????????</form>???????? ????</div> </template> <script> export?default?{ } </script>
然后在?resources >> assets >> js >> app.js
?中導(dǎo)入這個(gè)組件:
//?app.js require('./bootstrap'); window.Vue?=?require('vue'); Vue.component('form-component',?require('./components/FormComponent.vue')); const?app?=?new?Vue({ ????el:?'#app' });
最后在?home.blade.php
?中使用這個(gè)組件:
@extends('layouts.app') @section('content') <div?class="container"> ????<div?class="row?justify-content-center"> ???????<form-component></form-component> ????????<div?class="col-md-8"> ????????????TimeLines ????????</div> ????</div> </div> @endsection
為了監(jiān)聽前端資源變動(dòng),可以在項(xiàng)目根目錄下運(yùn)行如下命令監(jiān)聽前端資源變動(dòng)并實(shí)時(shí)編譯:
npm?run?watch
這樣,刷新?http://laratwitter.test/home
?頁(yè)面就可以看到變更后的效果了:
創(chuàng)建 Post 模型類及對(duì)應(yīng)數(shù)據(jù)庫(kù)遷移文件
下面我們來(lái)實(shí)現(xiàn)表單提交保存操作,首先創(chuàng)建一個(gè)模型類及對(duì)應(yīng)數(shù)據(jù)庫(kù)遷移文件:
php?artisan?make:model?Post?-m
編寫剛生成的數(shù)據(jù)庫(kù)遷移文件?create_posts_table.php
:
//?create_posts_table public?function?up() { ???Schema::create('posts',?function?(Blueprint?$table)?{ ???????$table->increments('id'); ???????$table->integer('user_id')->unsigned(); ???????$table->string('body',?140); ???????$table->timestamps(); ???????$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); ????}); }
運(yùn)行數(shù)據(jù)庫(kù)遷移命令:
php?artisan?migrate
現(xiàn)在可以在數(shù)據(jù)庫(kù)中看到剛創(chuàng)建的?posts
?數(shù)據(jù)表了。
接下來(lái)創(chuàng)建控制器?PostController
:
php?artisan?make:controller?PostController
定義關(guān)聯(lián)關(guān)系
在?User
?模型類中,我們需要定義一個(gè)關(guān)聯(lián)方法建立?Post
?模型和?User
?模型之間的關(guān)聯(lián)關(guān)系(一對(duì)多):
public?function?posts() { ???return?$this->hasMany(Post::class); }
相應(yīng)地,在?Post
?模型類中,也要定義與?User
?模型的關(guān)聯(lián)關(guān)系:
public?function?user() { ???return?$this->belongsTo(User::class); }
在數(shù)據(jù)庫(kù)中保存 Tweet
前面提到我們將通過(guò)?axios
?庫(kù)來(lái)發(fā)送 POST 請(qǐng)求到 Laravel 后端服務(wù)器,這個(gè)庫(kù)在我們運(yùn)行?npm install
?命令的時(shí)候已經(jīng)安裝好了,在開始處理請(qǐng)求發(fā)送與處理之前,我們先來(lái)定義請(qǐng)求路由,在?routes >> web.php
?文件中新增一個(gè)路由定義如下:
Route::post('tweet/save',?'PostController@store');
此外,還需要定義?Post
?模型類的?$fillable
?屬性來(lái)避免批量賦值異常:
protected?$fillable?=?['user_id',?'body'];
最后要做的準(zhǔn)備工作就是到?PostController.php
?中定義?store
?方法:
public?function?store(Request?$request,?Post?$post) { ????$newPost?=?$request->user()->posts()->create([ ????????'body'?=>?$request->get('body') ????]); ????return?response()->json($post->with('user')->find($newPost->id)); }
我們使用了關(guān)聯(lián)關(guān)系來(lái)保存 Post 數(shù)據(jù),它會(huì)自動(dòng)將當(dāng)前登錄用戶的?id
?作為保存 Post 的?user_id
?字段。
后端邏輯實(shí)現(xiàn)之后,接下來(lái)需要使用?axios
?庫(kù)類發(fā)送 POST 請(qǐng)求,我們將相應(yīng)邏輯寫到?FormComponent.vue
?組件中:
//?FormComponent.vue <template> ????<div?class="col-md-4"> ????????<form?@submit.prevent="saveTweet"> ????????????<div?class="form-group"> ????????????????<textarea? ????????????????????class="form-control"? ????????????????????rows="8"?cols="8"? ????????????????????maxlength="130" ????????????????????v-model="body" ????????????????????required> ????????????????</textarea> ????????????</div> ????????????<div?class="form-group"> ????????????????<button?class="btn?btn-primary"> ????????????????????Tweet ????????????????</button> ????????????</div> ????????</form>???????? ????</div> </template> <script> export?default?{ ????data()?{ ????????return?{ ????????????body:?'' ????????} ????}, ????methods:?{ ????????saveTweet()?{ ????????????axios.post('/tweet/save',?{body:?this.body}).then(res?=>?{ ????????????????console.log(res.data); ????????????}).catch(e?=>?{ ????????????????console.log(e); ????????????}); ????????} ????} } </script>
CSRF_TOKEN
?會(huì)默認(rèn)包含到每個(gè) POST 請(qǐng)求,所以不必手動(dòng)添加。現(xiàn)在,如果一切正常工作的話,你就可以成功保存 Post 數(shù)據(jù)并在響應(yīng)中獲取到 Post 對(duì)象及其關(guān)聯(lián)用戶:
創(chuàng)建一個(gè) Vue 事件
要想在前端顯示所有 Tweet,首先需要將它們顯示到時(shí)間線中,為此,我們需要?jiǎng)?chuàng)建一個(gè)事件。注意,這里不是要通過(guò)刷新頁(yè)面來(lái)獲取所有 Tweet,而是當(dāng)我們添加一條新的 Tweet 時(shí),在不刷新頁(yè)面的情況下在用戶時(shí)間線中顯示這條 Tweet。
為了實(shí)現(xiàn)這個(gè)功能,需要?jiǎng)?chuàng)建一個(gè)事件并觸發(fā)這個(gè)事件,我們通過(guò)時(shí)間線組件來(lái)監(jiān)聽事件觸發(fā)并基于該事件更新 UI??梢酝ㄟ^(guò)?Vuex?來(lái)實(shí)現(xiàn)該功能,但是現(xiàn)在,我們不想要深入存儲(chǔ)和動(dòng)作,只想將事情保持簡(jiǎn)單。
在?resources >> assets >> js
?目錄下創(chuàng)建一個(gè)名為?event.js
?的文件,并編寫代碼如下:
//?event.js import?Vue?from?'vue'; export?default?new?Vue();
然后將該文件導(dǎo)入?FormComponent.vue
:
//?FormComponent.vue <template> ????<div?class="col-md-4"> ????????<form?@submit.prevent="saveTweet"> ????????????<div?class="form-group"> ????????????????<textarea? ????????????????????class="form-control"? ????????????????????rows="8"?cols="8"? ????????????????????maxlength="130" ????????????????????v-model="body" ????????????????????required> ????????????????</textarea> ????????????</div> ????????????<div?class="form-group"> ????????????????<button?class="btn?btn-primary"> ????????????????????Tweet ????????????????</button> ????????????</div> ????????</form>???????? ????</div> </template> <script> import?Event?from?'../event.js'; export?default?{ ????data()?{ ????????return?{ ????????????body:?'', ????????????postData:?{} ????????} ????}, ????methods:?{ ????????saveTweet()?{ ????????????axios.post('/tweet/save',?{body:?this.body}).then(res?=>?{ ????????????????this.postData?=?res.data; ????????????????Event.$emit('added_tweet',?this.postData); ????????????}).catch(e?=>?{ ????????????????console.log(e); ????????????}); ????????????this.body?=?''; ????????} ????} } </script>
這樣,當(dāng)新提交數(shù)據(jù)被保存后,就可以觸發(fā)包含保存的 Tweet 和用戶信息的事件,監(jiān)聽該事件的監(jiān)聽器就可以捕獲數(shù)據(jù)并更新 UI。
創(chuàng)建時(shí)間線組件
接下來(lái),我們來(lái)定義監(jiān)聽 Tweet 發(fā)送成功事件的監(jiān)聽器。
在?resources >> assets >> js >> components
?目錄下新增一個(gè)?TimelineComponent.vue
?組件,編寫該組件代碼如下:
//?TimelineComponent.vue <template> ????<div?class="col-md-8?posts"> ????????<p?v-if="!posts.length">No?posts</p> ????????<div?class="media"?v-for="post?in?posts"?:key="post.id"> ????????????<img?class="mr-3"?/> ????????????<div?class="media-body"> ????????????????<div?class="mt-3"> ????????????????????<a?href="#">{{?post.user.name?}}</a> ????????????????</div> ????????????????<p>{{?post.body?}}</p> ????????????</div> ????????</div> ????</div> </template> <script> import?Event?from?'../event.js'; export?default?{ ????data()?{ ????????return?{ ????????????posts:?[], ????????????post:?{} ????????} ????}, ????mounted()?{ ????????Event.$on('added_tweet',?(post)?=>?{ ????????????this.posts.unshift(post); ????????}); ????} } </script>
這里我們定義了一個(gè)監(jiān)聽?added_tweet
?事件的監(jiān)聽器,當(dāng)該事件被觸發(fā)后,就可以執(zhí)行相應(yīng)的方法將數(shù)據(jù)渲染到時(shí)間線組件中。
和?FormComponent.vue
?組件一樣,在?app.js
?中注冊(cè)這個(gè)組件:
Vue.component('timeline-component',?require('./components/TimelineComponent.vue'));
我們專注高端建站,小程序開發(fā)、軟件系統(tǒng)定制開發(fā)、BUG修復(fù)、物聯(lián)網(wǎng)開發(fā)、各類API接口對(duì)接開發(fā)等。十余年開發(fā)經(jīng)驗(yàn),每一個(gè)項(xiàng)目承諾做到滿意為止,多一次對(duì)比,一定讓您多一份收獲!