###### tags: `Laravel教學已拍`
# [Laravel進階] Livewire核心觀念3:組件渲染
大家好,我是哥布林工程師,今天繼續來分享Livewire,來聊聊組件渲染相關的一些知識點
對了 如果你是第一次來到我們頻道的話,歡迎收看我們的課程
哥布林挨踢頻道是專注於電腦科學相關的課程
每週四下午6點都有新的影片上線
如果聽完今天的單元覺得對你有幫助的話
請幫忙給影片按著讚並訂閱我們的頻道唷
## 加入組件到視圖
首先,如果要加入Livewire組件,最簡單的方式就是使用 `<livewire:組件名稱>` 標籤,像是這樣:
```
<div>
<livewire:show-posts />
</div>
```
或者也可以使用 Blade 的 @livewire 指令
`@livewire('show-posts’)`
事實上這兩個寫法的功能都是相同的,不過要採用標籤的形式來撰寫是限定 Laravel 7 以上的版本,這點請特別注意
假如你的 Livewire 組件是放在子資料夾內,可以在名字前透過點語法來說明其完整的命名空間為何,像這樣
`<livewire:nav.show-posts />`
## 傳入參數
接著來聊聊傳入參數的知識點
為了讓組件更為好用,你往往需要傳入額外參數到組件內來達到傳遞資料的目的,接著就來舉個例子,假如我們有一個 show-post 組件,能夠這樣寫來傳入 $post 模型
`<livewire:show-post :post="$post”>`
如果是 Blade 指令的版本,則可以這樣寫
`@livewire('show-post', ['post' => $post])`
你可能會想知道,如果參數傳入之後,組件將要怎麼接收參數呢?
很簡單, Livewire 將會自動將參數分配給同名的屬性,比如像剛才的例子,假如 show-post 組件有一個同樣名為 $post 的屬性,它將會被自動的賦值
```
class ShowPost extends Component
{
public $post;
...
}
```
假如很不幸的,因未知原因自動賦值失敗的話,沒關係,你還是可以透過 mount() 來自己完成賦值,像是這樣
```
class ShowPost extends Component
{
public $title;
public $content;
public function mount($post)
{
$this->title = $post->title;
$this->content = $post->content;
}
...
}
```
那什麼情況會導致賦值失敗勒?
根據我的測試如果你的參數名稱有下橫線的話就會無法正常傳值
所以命名時請特別注意
既然說到 mount() ,有件事你應該要知道
在 Livewire 組件中,你應該使用 mount() 而非建構子 __construct() 來完成屬性的初始化工作。而它就如同控制器的方法一樣,你能夠利用型別提示的依賴注入技巧在參數上
```
use \Illuminate\Session\SessionManager;
class ShowPost extends Component
{
public $title;
public $content;
public function mount(SessionManager $session, $post)
{
$session->put("post.{$post->id}.last_viewed", now());
$this->title = $post->title;
$this->content = $post->content;
}
...
}
```
## 從路由設定組件
接著聊聊渲染與路由有關的知識點,假如整個頁面就是一個 Livewire 組件,你其實能夠在路由規則上直接傳入組件,將之當作控制器使用,省去還要額外撰寫控制器類別
```
//routes\web.php
Route::get('/post', ShowPosts::class);
```
預設情況下, Livewire 將會渲染 ShowPosts 組件的內容到 {{ $slot }},也就是插槽,預設的視圖為 resources/views/layouts/app.blade.php,這個檔案裡頭的內容會像這樣
```
<head>
@livewireStyles
</head>
<body>
{{ $slot }}
@livewireScripts
</body>
```
假如因為專案的需要,你想要改用其他視圖檔案而非預設的 layouts/app.blade.php,你能夠複寫 livewire.layout 設定檔的畫面這個選項來達到
`'layout' => ‘app.other_default_layout' `
而如果你希望動態的調整而不透過設定,也就是在程式中去判斷要使用的視圖,你能夠在 render() 後面接著使用 layout(),像是這樣
```
class ShowPosts extends Component
{
...
public function render()
{
return view('livewire.show-posts')
->layout('layouts.base');
}
}
```
假如你使用的不是預設的組件插槽,你能夠接著呼叫 slot()來指定正確的插槽名稱
```
public function render()
{
return view('livewire.show-posts')
->layout('layouts.base')
->slot('main');
}
```
當然,Livewire 1.x所使用的傳統 Blade layout語法還是管用的,你依然可以使用 @extends,假如你的父視圖像這樣:
```
<head>
@livewireStyles
</head>
<body>
@yield('content')
@livewireScripts
</body>
```
你就需要把 layout() 改成使用 extends()
```
public function render()
{
return view('livewire.show-posts')
->extends('layouts.app');
}
```
假如你需要指定組件所要渲染的 section 為何,你也能夠透過 section() 來加以指定
```
public function render()
{
return view('livewire.show-posts')
->extends('layouts.app')
->section('content');
}
```
假如你需要從組件類別將資料傳入 layout ,也沒問題。你能夠接著呼叫 layout(),並透過其第二參數來傳遞資料
```
public function render()
{
return view('livewire.show-posts')
->layout('layouts.base', ['title' => 'Show Posts'])
}
```
看起來 Livewire 所提供的組件渲染功能是非常完整的,不管你的專案再複雜都能夠加以因應才對
## 取得路徑參數
之前我們都是在控制器方法中去取用路徑參數,因為我們不再使用控制器, Livewire 會試著去模擬一個類似的行為,也就是透過 mount(),像這個例子:
```
//routes\web.php
Route::get('/post/{id}', ShowPost::class);
//app\Http\Livewire\ShowPost.php
class ShowPost extends Component
{
public $post;
public function mount($id)
{
$this->post = Post::find($id);
}
...
}
```
你看, mount() 在組件中就扮演著類似控制器方法的角色,它同樣可以取用路徑參數。比如你訪問 /post/123, $id 參數傳入 mount() 將會包含123的這個值
## Route Model Binding
說到 Laravel 所自帶的 Route Model Binding ,讓我們能夠便利的取得該主鍵的對應資料,而好消息是這個功能在 Livewire 同樣適用,請看下面這個例子:
```
//routes\web.php
Route::get('/post/{post}', ShowPost::class);
//app\Http\Livewire\ShowPost.php
class ShowPost extends Component
{
public $post;
public function mount(Post $post)
{
$this->post = $post;
}
}
```
假如你用的是 PHP 7.4或者是以上版本,你還能夠針對類別屬性做型別提示, Livewire 也會自動地幫你進行 Route Model Binding。比如下面組件的 $post 屬性將會被自動注入,在 mount() 內不需要做任何事情,讓工作變得更為簡單
但是特別提醒如果你環境的 PHP 版本低於7.4的話,將會出現語法錯誤的提示,表示你的 PHP 版本不足,請記得去做升級的動作
```
//app\Http\Livewire\ShowPost.php
class ShowPost extends Component
{
public Post $post;
}
```
## 組件的render()
最後聊一下 render() ,Livewire 組件的 render() 會在頁面初次載入的時候被呼叫。假如是很簡單的組件,你不需要自己定義 render(),因為生成的 Livewire 根組件就包含了一個動態的 render()
一般而言,在 render() 內被預期要回傳一個 Blade 視圖,因此,你能夠將之當做是一個控制器方法,請看下面這個例子:
```
//app/Http/Livewire/ShowPosts
class ShowPosts extends Component
{
public function render()
{
return view('livewire.show-posts', [
'posts' => Post::all(),
]);
}
}
```
```
//resources/views/livewire/show-posts.blade.php
<div>
@foreach ($posts as $post)
@include('includes.post', $post)
@endforeach
</div>
```
至於組件視圖的部分,有一點是新朋友要特別注意的
就是根據官方文件的記載
請務必確認你的 Blade 視圖內只有一個根元素,以免出現錯誤
而根據我自己做測試如果根元素有兩個以上的話
組件內容是可以正常地顯示 但會否導致其他功能出現錯誤就不清楚了
建議還是最好避免,以免自爆
另外,除了回傳 Blade 視圖檔案之外
假如內容簡單的話,也可以在 render() 直接回傳一個包含 Blade 佈局的字串
也就是所謂的 inline 組件
關於 inline 組件更多的細節,可以參考我前一個關於建立組件的教學影片
有需要的可以參考上方資訊卡
inline 組件的類別長的就像是這樣
```
//app/Http/Livewire/DeletePost
class DeletePost extends Component
{
public Post $post;
public function delete()
{
$this->post->delete();
}
public function render()
{
return <<<'blade'
<div>
<button wire:click="delete">Delete Post</button>
</div>
blade;
}
}
```
這裡直接提供懶人包,如果需要生成 inline 組件的話,可以加入 --inline 選項,像這樣 php artisan make:livewire delete-post --inline
以上就是今天關於組件渲染的所有知識點
如果你有任何問題歡迎在底下留言
假如你覺得這個單元有讓你學到東西的話
拜託給影片按個讚並訂閱我們的頻道
您的支持是讓頻道繼續下去最大的動力
我們下個單元再見,掰掰
## 時間軸
影片開始 00:00
加入組件到視圖 00:50
傳入參數 05:00
從路由設定組件 12:43
取得路徑參數 24:17
Route Model Binding 28:02
組件的render() 31:02
## 相關鏈接
【Livewire核心知識篇: 安裝與建立組件】
https://youtu.be/uHgFVTnSl5g
【Livewire快速入門】
https://youtu.be/H346Fat-0V0
【一頁式網站實作攻略】
https://youtu.be/wXg0ZdH9Kl0
【部落格網站實作攻略】
https://youtu.be/Jv7JPnWwxYg
## 行銷稿
各位朋友晚安,我是每天在空中陪著你的哥布林工程師,又有新的消息想要和大家報告
甚麼消息呢? 你猜猜今天是禮拜幾?
星期四,猜對了。也就是哥布林挨踢頻道發布新影片的日子,這周的影片就在剛剛上線拉,而這件事情讓我非常的興奮~
影片的主題是談 Livewire 組件的渲染,目的在讓你明白該如何在視圖去使用組件。這主題很有用,但不是讓我興奮最主要的原因
我掛保證的告訴大家,這支影片是我從開始錄製影片以來最好的一支影片
從企劃 . 試拍 . 練習流程 . 正式拍攝 . 素材製作 . 口白優化 . 影片後製 這裡頭的每一個環節,都做了新的嘗試以及優化,目的是希望讓想要學習技術的朋友,能夠有更好的學習體驗
如果今天晚上沒有約會的話,何不花個35分鐘看下這支影片,累積自己的技術實力絕對是最好的投資,你說對嗎?
終於要把這份成果交給大家去評比,你覺得這支影片對你的學習有幫助嗎? 不管你是喜歡或者是覺得有那些地方可以改進,都歡迎留言告訴我唷!
https://youtu.be/ifz8xUPYQTA