Livewire-Blog (用 Laravel 8 + Jetstream 構建的一個開源部落格)

youxx發表於2020-10-09

背景

Laravel 8 釋出近一個月了,這次改動比較吸引我的就是 Jetstream 全家桶。在沒釋出之前我沒接觸過 Livewire 以及前端的 Tailwindcssalpinejs。但是我是一個比較喜歡嘗試新技術的人。在商業化的專案去實踐顯然是不可取的。所以我在國慶開始的時候就打算利用假期的時間去折騰下部落格試試,瞭解它的特點。再去專案中對應的去使用。經過一段時間的折騰我發現這玩意挺香的。當然也有一些坑,我也會分享出來。

Livewire-Blog

github 程式碼地址 喜歡的請star?下 ?

部落格線上地址

PC端介面效果

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

移動端介面效果

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

功能分析

搜尋案例

Livewire 最大的優點的就是跟前端介面動態互動,比如我搜尋 Laravel 的時候他可以配合前端監聽我的輸入。實時通過 api 呼叫後臺的資料返回給前端。而這些 api 是無須你在編寫的。它的核心檔案 LivewireServiceProvider 已經註冊。有興趣的同學可以看下這個核心檔案。

php artisan make:livewire search 生成 search.blade.php Search.php 檔案

  • search.blade.php

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

  • Search.php

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

  • 檢視效果

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

評論案例

評論裡面會用到 Livewire 的元件全域性事件相互通訊

  • 需求分析

Livewire-Blog  (用 Laravel 8 + Jetstream 構建的一個開源部落格)

  • 程式碼實現

    php artisan make:livewire AddComment
    php artisan make:livewire ShowComment

  • AddComment

<?php

namespace App\Http\Livewire;

use App\Models\CommentModel;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Livewire\Component;
class AddComment extends Component
{
    /**
     * @var string
     */
    public $content;
    /**
     * @var int
     */
    public $post_id;
    /**
     * @var int
     */
    public $parent_id;
    /**
     * @var string
     */
    public $comment_composing_box_id;
    /**
     * @var string
     */
    public $preview_box_id;
    /**
     * @var string
     */
    public $target_id;

    /**
     * @var array
     */
    protected $rules = [
        'content' => 'required',
    ];
    /**
     * @var array
     */
    protected $messages = [
        'content.required' => '評論不能為空!',
    ];

    public function mount(int $postId, CommentModel $comment, int $time = 0): void
    {
        $this->post_id = $postId;
        $this->parent_id = empty($comment->id) ? 0 : ($comment->parent_id ? $comment->parent_id : $comment->id);
        $this->target_id = empty($comment->id) ? 0 : $comment->id;
        $this->content = ($time > 0 && ! empty($comment->user)) ? '@'.$comment->user->name.':' : '';
        $this->comment_composing_box_id = 'comment-composing-box-'.Str::random(10);
        $this->preview_box_id = 'preview-box'.Str::random(10);
    }

    public function submit(): void
    {
        if ($this->check()) {
            $validatedData = $this->validate();
            $data = [
                'content'   => $validatedData['content'],
                'user_id'   => Auth::user()->id,
                'parent_id' => $this->parent_id,
                'post_id'   => $this->post_id,
                'target_id' => $this->target_id,
            ];

            CommentModel::create($data);

            $this->reset('content');

            $this->emitTo('show-comment', 'create', $this->post_id);

            session()->flash('message', '新增評論成功!');
        }
    }

    public function userCommentLimit(MessageBag &$messageBag): void
    {
        $time = Cache::get(user_comment_limit_key()) ?? 0;
        $limit_day_time = config('cache.user_comment_limit.day_time', 10);

        if ($limit_day_time < $time) {
            $messageBag->add('content', Str::replaceFirst('?', $limit_day_time, '使用者每天最多隻能回覆 ? 評論'));
        } else {
            Cache::put(user_comment_limit_key(), $time + 1, Carbon::today()->addDay());
        }
    }

    /**
     * @param MessageBag $messageBag
     */
    public function mustLogin(MessageBag &$messageBag): void
    {
        Auth::guest() && $messageBag->add('content', '使用者需要登陸!');
    }

    /**
     * @return bool
     */
    public function check(): bool
    {
        $messageBag = $this->getErrorBag();
        $this->userCommentLimit($messageBag);
        $this->mustLogin($messageBag);

        return $messageBag->count() === 0;
    }

    /**
     * @return View
     */
    public function render(): View
    {
        return view('livewire.add-comment');
    }
}
  • ShowComment
<?php

namespace App\Http\Livewire;

use App\Models\PostModel;
use App\Repositories\BlogRepository;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Livewire\Component;

class ShowComment extends Component
{
    /**
     * @var int
     */
    public $postId;
    /**
     * @var Collection
     */
    public $comments;
    /**
     * @var int
     */
    public $comments_count = 0;
    /**
     * @var array
     */
    protected $listeners = ['create' => 'getCommens'];

    /**
     * @param $postIds
     */
    public function mount(PostModel $post): void
    {
        $this->postId = $post->id;
        $this->comments = $post->comments;
        $this->comments_count = $post->comments->count() ?? 0;
    }

    /**
     * $params.
     */
    public function getCommens(int $postId): void
    {
        $post = BlogRepository::getPostById($postId);
        $this->comments = $post->comments;
        $this->comments_count = $post->comments->count() ?? 0;
    }

    /**
     * @return View
     */
    public function render(): View
    {
        return view('livewire.show-comment');
    }
}
  • 分析
    裡面比較重要的是 emitTo 這個的意思,就是你這個元件處理完成了需要通知到誰,比如通知 ShowComment, 就是 $this->emitTo('show-comment', 'create', $this->post_id);元件名稱可以通過列印 ShowComment::getName()獲得。

  • 我遇到的坑

    • 評論我是要迴圈巢狀的。如果每個show-comment.blade.php 去再巢狀自己,emitTo 就會通知很多個 ShowComment,我暫時沒看到 元件可以根據 名字+id 去通知同步的。後面我用的 include 巢狀迴圈模版。有興趣的大家可以看下我程式碼。
  • AddComment元件 我是要去驗證使用者是否登陸的,無法通過中介軟體實現。我後面是在元件方法裡面去驗證的。如果大家有好的辦法也可以告訴我。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章