iT邦幫忙

2021 iThome 鐵人賽

0
Modern Web

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

Day 33 | 常見 Livewire 問題:解決 Livewire.on() 沒有作用的問題

這個問題其實在 Day8 的文章有稍微提到過,但大多數人看文件時都大致看一下而會忽略一些小細節,包含我也是 XD。且 Livewire 官方文件並沒有清楚列出避免這個問題的方法。因此再拉出來講解,希望能幫助到遇到這個問題的人。


一、何時會用到 Livewire.on()

在使用 $emit('foo') 觸發後端的 Listener 的同時也會觸發到前端的 Livewire.on('foo'),可以理解是註冊成一個監聽。

註:不管是在頁面按鈕上的 wire:click="$emit('foo')" 或是後端的 $this->emit('foo') 都是一樣的!

<script>
Livewire.on('foo', () => {
    ...
})
</script>

二、找出無效的原因

先來看一下錯誤訊息:

Uncaught ReferenceError: Livewire is not defined

嗯嗯,看起來是沒有定義 Livewire 呢!那為什麼會沒有定義呢,不是外面早就引入過 @livewireScripts了嗎?

照官方文件給的 Layout佈局 會像是這樣子:

<head>
    @livewireStyles
</head>
<body>
    {{ $slot }}
 
    @livewireScripts
</body>

寫在 Livewire元件 中的程式碼都會被填在 {{ $slot }} 的位置,因此等於在 JavaScript 還沒引入 Livewire 時就先用到了 Livewire,從而導致出錯。


三、解決方法

知道問題後要解決也很簡單。

第一種、直接把 @livewireScripts 提到 {{ $slot }} 上面。

不過不是推薦,因為還是建議把 JS 都放在 <Body> 的最下面。

<body>
	@livewireScripts
	{{ $slot }}
</body>

第二種、使用 @stack 跟 @push

或是使用 @yield 跟 @section,這兩者差別是在於 @stack/push 可以堆棧多組來自不同 components 的內容。而 @yield/section 只能用一次。為了日後有可能會用到導致要改就要全部改,不如一開始就直接用 @stack

<body>
    {{ $slot }}

    @livewireScripts
    
    @stack('scripts')
</body>

在 Livewire Blade 內:

<div>
    <button wire:click="$emit('foo')">CLICK</button>
</div>

@push('scripts')
	<script>
	    Livewire.on('foo', () => {
	        ...
	    })
	</script>
@endpush

結論: @livewireScripts 引入的位置要比你的 <script> 還上面


上一篇
Day 32 | 常見 Livewire 問題:與 Controller 兼容的幾種方式
系列文
Laravel Livewire:不用 Vue 跟 jQuery 居然也能讓 Laravel 的畫面動起來 ?!34

尚未有邦友留言

立即登入留言