不寫 JS,就讓網站變成 SPA!Laravel Livewire 初體驗(下)

sharkHead 程式技術 2個月前 • 0

此篇文章為下篇
還沒有看過上篇的朋友,建議可以先看完上篇

不寫 JS,就讓網站變成 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 class="btn btn-primary" wire:click="store">回覆</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 class="btn btn-danger"
                                    onclick="confirm('您確定要刪除此回覆嗎?') || event.stopImmediatePropagation()"
                                    wire:click="destroy({{ $reply->id }})">
                                        刪除
                                    </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()
        ]);
    }
}

一個簡單的即時更新留言板就這麼完成啦!

%E5%9C%96%E7%89%87%282%29.png

 

Livewire 的上手難度很低,呈現的效果卻非常好
雖然面對複雜的前端架構應該還是無法與目前主流的前端框架(React 與 Vue)相比
但是如果網站只需要一些簡單的前後端資料交換,那麼 Livewire 可以說是非常不錯的選擇
感謝您的閱讀~

參考資料
Laravel Livewire


sharkHead

PHP 與 Python 菜雞工程師
最近在努力學習 TypeScript,希望可以突破慧根的限制