不寫 JavaScript,就讓網站變成 SPA!Laravel Livewire 初體驗 (下)
此篇文章為下篇,還沒有看過上篇的朋友,建議可以先看完上篇文章。
繼續之前的文章,我們已經有了回覆區塊,也完成了對回覆表單的內容進行即時驗證,本篇文章會完成將回覆的內容存進資料庫,並在回覆表單底下顯示所有的回覆。
新建回覆的 Model 與資料表
首先在專案內輸入以下指令,新建一個 Reply 的 Model 與 migration。
php artisan make:model Reply -m
上述指令會生成兩個檔案。
- app/Models/
Reply.php
- database/migrations/
2021_02_05_155509_create_replies_table.php
migration 檔名前半段的日期是抓取現在的時間。
因為我們需要存儲留言內容,所以得先在 Reply.php
中設定 $fillable
屬性。
<?php
...
class Reply extends Model
{
use HasFactory;
// fillable 屬性是用來設定可以被批量賦值的資料表欄位
protected $fillable = ['content'];
}
再來是設定 migration 檔案,新增 content 這個欄位。
<?php
...
class CreateRepliesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('replies', function (Blueprint $table) {
$table->id();
// 新增一個 content 欄位
$table->string('content')->comment('回覆內容');
$table->timestamps();
});
}
...
}
執行 migrate 指令,創建資料表。
php artisan migrate
儲存留言內容與顯示所有留言
先在 resources/views/livewire/replies.blade.php
的回覆表單中新增一個送出回覆的按鈕。
...
<div class="d-flex justify-content-between">
<!-- 錯誤訊息顯示 -->
<div class="d-flex justify-content-center align-items-center">
@error('content') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<!-- 使用 wire:click 觸發 Replies.php 的 store 方法 -->
<button wire:click="store" class="btn btn-primary">回覆</button>
</div>
...
可以發現這裡使用新的 Livewire component 語法 wire:click="store"
,當按鈕被點擊時,就會觸發 app/Http/Livewire/Replies.php
的 store()
方法。
因為 Replies.php
中還沒有 store()
方法,我們需要將其補上。
<?php
...
use App\Models\Reply;
class Replies extends Component
{
...
// 儲存回覆
public function store()
{
// 通過驗證才會進行後續操作
$this->validate();
// 儲存留言至資料庫
Reply::create([
'content' => $this->content,
]);
// 清空回覆表單的內容
$this->content = '';
}
public function render()
{
return view('livewire.replies');
}
}
這個時候可以嘗試留言並送出回覆表單,成功送出表單的話,表單內容就會被清空,連線至資料庫查看,應該就會發現裡面多了一筆剛剛留言的資料。
顯示回覆列表與刪除回覆
接下來實作顯示所有回覆的回覆列表,當留言回覆成功時,下方的回覆列表會立即顯示剛剛成功的留言。
首先在 replies.php
中的回覆表單底下新增個回覆列表區塊,並用剛剛的 wire:click
,實作一個刪除回覆的按鈕。
<div>
<!-- 評論回覆 -->
...
<!-- 回覆列表 -->
@if ($replies->count() > 0)
<div class="card shadow mb-4">
<div class="card-body p-4">
<ul class="list-group list-group-flush">
@foreach ($replies as $reply)
<li class="list-group-item" name="reply-{{ $reply->id }}" id="reply-{{ $reply->id }}">
<div class="row">
<div class="col-10 d-flex justify-content-start align-items-center">
<!-- 回覆內容 -->
<div class="d-flex flex-column">
<div class="card-text">
{!! nl2br(e($reply->content)) !!}
</div>
</div>
</div>
<div class="col-2 d-flex justify-content-end align-items-center">
<!-- 回覆刪除按鈕 -->
<button onclick="confirm('您確定要刪除此回覆嗎?') || event.stopImmediatePropagation()"
wire:click="destroy({{ $reply->id }})" class="btn btn-danger">
刪除
</button>
</div>
</div>
</li>
@endforeach
</ul>
</div>
</div>
@endif
</div>
這裡使用 $replies
這個變數接收所有的回覆資料,但目前後端並未傳送此資料,等會需要在 Replies.php
中補上。
一般來說,刪除資料都需要經過二次確認避免使用者誤點,這樣使用者體驗也會比較好,因此在這裡加上下面一行,確保按下刪除按鈕後會對使用者進行二次確認。
onclick="confirm('您確定要刪除此回覆嗎?') || event.stopImmediatePropagation()"
更新 Replies.php
,補上 destroy()
方法,還有使用 ORM 操作取得所有回覆資料並傳送至前端。
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Reply;
class Replies extends Component
{
...
// 刪除回覆
public function destroy(Reply $reply)
{
$reply->delete();
}
public function render()
{
return view('livewire.replies', [
// 傳送所有回覆資料至前端
'replies' => Reply::all()
]);
}
}
一個簡單的即時更新留言板就這麼完成啦!
Livewire 的上手難度很低,呈現的效果卻非常好,雖然面對複雜的前端架構應該還是無法與目前主流的前端框架(React 與 Vue)相比。
但是如果網站只需要一些簡單的前後端資料交換,那麼 Livewire 可以說是非常不錯的選擇!
感謝您的閱讀~