iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
Modern Web

Laravel Livewire:不用 Vue 跟 jQuery 居然也能讓 Laravel 的畫面動起來 ?!系列 第 8

Day 08 | 觸發事件

昨天提到了互動事件(Action)基本上能解決大部分頁面中互動的需求,但若要能夠跨元件來進行互動,例如呼叫其他元件中的 Function 就要靠今天的 $emit 事件啦~

Emit 事件

不光是能夠從 Template Blade 中使用,也能夠從 Livewire 元件中的 Function 使用,甚至還能在 JavaScript 中呼叫使用。

在 Template Blade 使用

<button wire:click="$emit('postAdded')">

在 Livewire 元件中使用

$this->emit('postAdded');

在 JavaScript 中使用

<script>
    Livewire.emit('postAdded')
</script>

設置監聽 - Event Listeners

不過在使用 emit 前必須先在各個有要用到的元件中先宣告監聽才能夠成功透過 $emit 呼叫該元件中的 Function。

注意: 這邊是很多人常常忘記做的步驟而導致怎樣都呼叫不到,且 emit 是全域呼叫並不會提示是否呼叫成功或是報錯。

class Day8 extends Component
{
    ...
    
    protected $listeners = ['toggleTitle' => 'toggleTitle'];

    public function render()
    {
        return view('livewire.example.day8');
    }

    public function toggleTitle()
    {
        ...
    }
}

外面 $emit 的名稱也可以跟實際函數名稱的不一樣,像是這邊我這個元件中使用的是 setTitleVisible () 而外面一樣透過 $emit('toggleTitle') 來呼叫。

protected $listeners = ['toggleTitle' => 'setTitleVisible'];

傳遞參數

要傳遞參數也是非常簡單的事:

$this->emit('postAdded', $post->id);
   protected $listeners = ['postAdded'];
 
    public function postAdded($id)
    {
        ...
    }

範圍 - Scoping Events

由於 $emit 的範圍可涵蓋至目前頁面上所有的 Livewire,也能做全域呼叫使用,換句話說就是能觸發不同 Livewire 元件中同名的 Function,可以參考 Github 上 Day8 的範例。但有時候並不需要呼叫到全部的元件,那這時候就有以下幾種方法可以只呼叫特定元件中的 Function:

* 只呼叫父元件 emitUp

$this->emitUp('postAdded');
<button wire:click="$emitUp('postAdded')">

* 透過元件名稱呼叫 emitTo

$this->emitTo('counter', 'postAdded');
<button wire:click="$emitTo('counter', 'postAdded')">

* 只呼叫自己本身 emitSelf

$this->emitSelf('postAdded');
<button wire:click="$emitSelf('postAdded')">

在 JavaScript 中監聽事件

資料儲存成功後,要在頁面顯示成功的訊息還是需要透過 JS 來執行,畢竟那些放在按鈕中的 wire:click() 事件沒辦法回傳值,也沒辦法在 PHP 呼叫 JS 的 Function。那就只能夠過這個方法來做產生操作回饋。

因此我們可以在 bladescript 區塊中建立一個監聽器,並透過 alert 來顯示操作成功的訊息:

<script>
Livewire.on('postAdded', () => {
    alert('文章已經發布囉!');
})
</script>

之後的 $emit('postAdded') 也會觸發上面的 JS 區塊囉 ~

注意:這裡的 <script> 必須放在 Layout 的頁面才會生效,或者使用 @stack('scripts')@push('scripts') 來將 JS 的部分塞回 Layout 中才會生效,程式碼可以參考我的 Day8 示範。

*如果覺得複雜建議使用下方瀏覽器監聽的方法,會簡單很多!!

觸發瀏覽器的監聽事件

也可以直接觸發瀏覽器的監聽事件,但這邊就要使用 dispatchBrowserEvent () 而不是 emit()

$this->dispatchBrowserEvent('postAdded');

blade 上則要用 window.addEventListener 來建立監聽:

<script>
window.addEventListener('postAdded', () => {
    alert('文章已經發布囉!');
})
</script>

範例

GitHub 網址在這邊

運行之後打開 http://127.0.0.1:8000/day8 就能看到今天的範例啦!

檔案的話分別在:
app\Http\Livewire\Example\Day8.php
resources\views\livewire\example\day8.balde.php

今天的範例會演示:

  1. 透過 $emit 同時呼叫 Day8Day8Child 中的 toggleTitle()
  2. 透過 JavaScript 來接收 $emit 的事件。
  3. 透過 瀏覽器的監聽器 來接收 dispatchBrowserEvent 事件。

上一篇
Day 07 | 互動事件
下一篇
Day 09 | Livewire 生命週期勾 Lifecycle Hooks
系列文
Laravel Livewire:不用 Vue 跟 jQuery 居然也能讓 Laravel 的畫面動起來 ?!34

尚未有邦友留言

立即登入留言