事件

您是视觉学习者吗?
通过我们深入的屏幕录制掌握 Livewire
立即观看

Livewire 提供了一个强大的事件系统,您可以使用它在页面上的不同组件之间进行通信。因为它在底层使用浏览器事件,您还可以使用 Livewire 的事件系统与 Alpine 组件甚至纯香草 JavaScript 进行通信。

要触发事件,您可以在组件的任何位置使用 dispatch() 方法,并从页面上的任何其他组件侦听该事件。

分发事件

要从 Livewire 组件分发事件,您可以调用 dispatch() 方法,向其传递事件名称以及您要随事件一起发送的任何其他数据。

下面是一个从 CreatePost 组件分发 post-created 事件的示例

use Livewire\Component;
 
class CreatePost extends Component
{
public function save()
{
// ...
 
$this->dispatch('post-created');
}
}

在此示例中,当调用 dispatch() 方法时,将分发 post-created 事件,并且页面上正在侦听此事件的每个其他组件都将收到通知。

您可以通过将数据作为第二个参数传递给 dispatch() 方法来随事件传递其他数据

$this->dispatch('post-created', title: $post->title);

侦听事件

要在 Livewire 组件中侦听事件,请在希望在分派给定事件时调用的方法上方添加 #[On] 属性

确保导入属性类

确保导入所有属性类。例如,以下 #[On()] 属性需要以下导入 use Livewire\Attributes\On;

use Livewire\Component;
use Livewire\Attributes\On;
 
class Dashboard extends Component
{
#[On('post-created')]
public function updatePostList($title)
{
// ...
}
}

现在,当 post-created 事件从 CreatePost 分派时,将触发网络请求,并且将调用 updatePostList() 操作。

如你所见,随事件发送的其他数据将作为其第一个参数提供给操作。

侦听动态事件名称

有时,你可能希望在运行时使用组件中的数据动态生成事件侦听器名称。

例如,如果你想将事件侦听器限定为特定 Eloquent 模型,则可以将模型的 ID 追加到事件名称,如下所示

use Livewire\Component;
use App\Models\Post;
use Livewire\Attributes\On;
 
class ShowPost extends Component
{
public Post $post;
 
#[On('post-updated.{post.id}')]
public function refreshPost()
{
// ...
}
}

如果上述 $post 模型的 ID 为 3,则 refreshPost() 方法将仅由名为 post-updated.3 的事件触发。

侦听来自特定子组件的事件

Livewire 允许你在 Blade 模板中直接侦听单个子组件上的事件,如下所示

<div>
<livewire:edit-post @saved="$refresh">
 
<!-- ... -->
</div>

在上述情况下,如果 edit-post 子组件分派 saved 事件,则将调用父级的 $refresh,并且父级将被刷新。

你可以传递任何方法(就像通常对 wire:click 所做的那样),而不仅仅是传递 $refresh。以下是如何调用可能执行关闭模态对话框等操作的 close() 方法的示例

<livewire:edit-post @saved="close">

如果子级连同请求分派参数,例如 $this->dispatch('close', postId: 1),则可以使用以下语法将这些值转发给父级方法

<livewire:edit-post @saved="close($event.detail.postId)">

使用 JavaScript 与事件交互

当你从应用程序内的 JavaScript 与 Livewire 的事件系统进行交互时,Livewire 的事件系统将变得更加强大。这解锁了应用程序中任何其他 JavaScript 与页面上的 Livewire 组件进行通信的能力。

在组件脚本内部侦听事件

你可以轻松地从一个 @script 指令中侦听组件模板内部的 post-created 事件,如下所示

@script
<script>
$wire.on('post-created', () => {
//
});
</script>
@endscript

上面的代码段将侦听其注册组件内的 post-created 事件。如果组件不再位于页面上,则不再触发事件侦听器。

阅读有关在 Livewire 组件中使用 JavaScript 的更多信息 →

从组件脚本分派事件

此外,你可以从组件的 @script 中分派事件,如下所示

@script
<script>
$wire.dispatch('post-created');
</script>
@endscript

当运行上述 @script 时,post-created 事件将分派到其定义组件中。

若要仅将事件分派到脚本所在的组件,而不分派到页面上的其他组件(防止事件“冒泡”),你可以使用 dispatchSelf()

$wire.dispatchSelf('post-created');

你可以通过将对象作为第二个参数传递给 dispatch() 来向事件传递任何其他参数

@script
<script>
$wire.dispatch('post-created', { refreshPosts: true });
</script>
@endscript

你现在可以从 Livewire 类和其他 JavaScript 事件侦听器访问这些事件参数。

以下是在 Livewire 类中接收 refreshPosts 参数的示例

use Livewire\Attributes\On;
 
// ...
 
#[On('post-created')]
public function handleNewPost($refreshPosts = false)
{
//
}

你还可以从事件的 detail 属性中从 JavaScript 事件侦听器访问 refreshPosts 参数

@script
<script>
$wire.on('post-created', (event) => {
let refreshPosts = event.detail.refreshPosts
 
// ...
});
</script>
@endscript

阅读有关在 Livewire 组件中使用 JavaScript 的更多信息 →

从全局 JavaScript 侦听 Livewire 事件

或者,你可以使用 Livewire.on 从应用程序中的任何脚本全局侦听 Livewire 事件

<script>
document.addEventListener('livewire:init', () => {
Livewire.on('post-created', (event) => {
//
});
});
</script>

上面的代码段将侦听页面上任何组件分派的 post-created 事件。

如果你出于任何原因希望移除此事件侦听器,你可以使用返回的 cleanup 函数执行此操作

<script>
document.addEventListener('livewire:init', () => {
let cleanup = Livewire.on('post-created', (event) => {
//
});
 
// Calling "cleanup()" will un-register the above event listener...
cleanup();
});
</script>

Alpine 中的事件

由于 Livewire 事件本质上是普通的浏览器事件,因此你可以使用 Alpine 侦听它们,甚至分派它们。

在 Alpine 中侦听 Livewire 事件

例如,我们可以使用 Alpine 轻松侦听 post-created 事件

<div x-on:post-created="..."></div>

上述代码段将侦听分配了 x-on 指令的 HTML 元素的任何 Livewire 组件的 post-created 事件。

要侦听页面上任何 Livewire 组件的事件,可以将 .window 添加到侦听器

<div x-on:post-created.window="..."></div>

如果要访问随事件发送的其他数据,可以使用 $event.detail

<div x-on:post-created="notify('New post: ' + $event.detail.title)"></div>

Alpine 文档提供了有关 侦听事件 的更多信息。

从 Alpine 分派 Livewire 事件

从 Alpine 分派出的任何事件都可以被 Livewire 组件拦截。

例如,我们可以轻松地从 Alpine 分派 post-created 事件

<button @click="$dispatch('post-created')">...</button>

与 Livewire 的 dispatch() 方法类似,可以通过将数据作为方法的第二个参数传递,将其他数据与事件一起传递

<button @click="$dispatch('post-created', { title: 'Post Title' })">...</button>

要了解有关使用 Alpine 分派事件的更多信息,请参阅 Alpine 文档

你可能不需要事件

如果你正在使用事件从子组件调用父组件上的行为,则可以使用 Blade 模板中的 $parent 直接从子组件调用操作。例如

<button wire:click="$parent.showCreatePostForm()">Create Post</button>

了解有关 $parent 的更多信息.

直接分派到另一个组件

如果你想使用事件在页面上的两个组件之间直接通信,可以使用 dispatch()->to() 修饰符。

下面是 CreatePost 组件直接向 Dashboard 组件分派 post-created 事件的示例,跳过侦听该特定事件的任何其他组件

use Livewire\Component;
 
class CreatePost extends Component
{
public function save()
{
// ...
 
$this->dispatch('post-created')->to(Dashboard::class);
}
}

向组件自身分发组件事件

使用 dispatch()->self() 修饰符,可以限制事件仅被触发它的组件拦截

use Livewire\Component;
 
class CreatePost extends Component
{
public function save()
{
// ...
 
$this->dispatch('post-created')->self();
}
}

从 Blade 模板分发事件

可以使用 $dispatch JavaScript 函数直接从 Blade 模板分发事件。当希望从用户交互(如按钮点击)触发事件时,这非常有用

<button wire:click="$dispatch('show-post-modal', { id: {{ $post->id }} })">
EditPost
</button>

在此示例中,当按钮被点击时,show-post-modal 事件将使用指定的数据分发。

如果希望直接向另一个组件分发事件,可以使用 $dispatchTo() JavaScript 函数

<button wire:click="$dispatchTo('posts', 'show-post-modal', { id: {{ $post->id }} })">
EditPost
</button>

在此示例中,当按钮被点击时,show-post-modal 事件将直接分发到 Posts 组件。

测试分发的事件

要测试组件分发的事件,请在 Livewire 测试中使用 assertDispatched() 方法。此方法检查在组件生命周期中是否分发了特定事件

<?php
 
namespace Tests\Feature;
 
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Livewire\CreatePost;
use Livewire\Livewire;
 
class CreatePostTest extends TestCase
{
use RefreshDatabase;
 
/** @test */
public function it_dispatches_post_created_event()
{
Livewire::test(CreatePost::class)
->call('save')
->assertDispatched('post-created');
}
}

在此示例中,测试确保在 CreatePost 组件上调用 save() 方法时,post-created 事件使用指定的数据分发。

测试事件侦听器

要测试事件侦听器,可以从测试环境分发事件,并断言预期操作已针对该事件执行

<?php
 
namespace Tests\Feature;
 
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Livewire\Dashboard;
use Livewire\Livewire;
 
class DashboardTest extends TestCase
{
use RefreshDatabase;
 
/** @test */
public function it_updates_post_count_when_a_post_is_created()
{
Livewire::test(Dashboard::class)
->assertSee('Posts created: 0')
->dispatch('post-created')
->assertSee('Posts created: 1');
}
}

在此示例中,测试分发 post-created 事件,然后检查 Dashboard 组件是否正确处理该事件并显示更新的计数。

使用 Laravel Echo 的实时事件

Livewire 与 Laravel Echo 很好的配对,使用 WebSocket 在网页上提供实时功能。

安装 Laravel Echo 是先决条件

此功能假定您已安装 Laravel Echo,并且 window.Echo 对象在应用程序中全局可用。有关安装 Echo 的更多信息,请查看 Laravel Echo 文档

侦听 Echo 事件

假设您在 Laravel 应用程序中有一个名为 OrderShipped 的事件

<?php
 
namespace App\Events;
 
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
 
class OrderShipped implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
 
public Order $order;
 
public function broadcastOn()
{
return new Channel('orders');
}
}

您可以像这样从应用程序的另一部分分发此事件

use App\Events\OrderShipped;
 
OrderShipped::dispatch();

如果您仅使用 Laravel Echo 在 JavaScript 中侦听此事件,它将类似于以下内容

Echo.channel('orders')
.listen('OrderShipped', e => {
console.log(e.order)
})

假设您已安装并配置 Laravel Echo,则可以在 Livewire 组件内侦听此事件。

下面是一个 `OrderTracker` 组件的示例,它正在侦听 `OrderShipped` 事件,以便向用户显示新订单的视觉指示

<?php
 
namespace App\Livewire;
 
use Livewire\Attributes\On;
use Livewire\Component;
 
class OrderTracker extends Component
{
public $showNewOrderNotification = false;
 
#[On('echo:orders,OrderShipped')]
public function notifyNewOrder()
{
$this->showNewOrderNotification = true;
}
 
// ...
}

如果您有包含变量的 Echo 通道(例如订单 ID),则可以通过 `getListeners()` 方法而不是 `#[On]` 属性来定义侦听器

<?php
 
namespace App\Livewire;
 
use Livewire\Attributes\On;
use Livewire\Component;
use App\Models\Order;
 
class OrderTracker extends Component
{
public Order $order;
 
public $showOrderShippedNotification = false;
 
public function getListeners()
{
return [
"echo:orders.{$this->order->id},OrderShipped" => 'notifyShipped',
];
}
 
public function notifyShipped()
{
$this->showOrderShippedNotification = true;
}
 
// ...
}

或者,如果您愿意,可以使用动态事件名称语法

#[On('echo:orders.{order.id},OrderShipped')]
public function notifyNewOrder()
{
$this->showNewOrderNotification = true;
}

如果您需要访问事件有效负载,可以通过传入的 `$event` 参数进行访问

#[On('echo:orders.{order.id},OrderShipped')]
public function notifyNewOrder($event)
{
$order = Order::find($event['orderId']);
 
//
}

私有和临场频道

您还可以侦听广播到私有和临场频道的事件

在继续之前,请确保您已为广播频道定义了 身份验证回调

<?php
 
namespace App\Livewire;
 
use Livewire\Component;
 
class OrderTracker extends Component
{
public $showNewOrderNotification = false;
 
public function getListeners()
{
return [
// Public Channel
"echo:orders,OrderShipped" => 'notifyNewOrder',
 
// Private Channel
"echo-private:orders,OrderShipped" => 'notifyNewOrder',
 
// Presence Channel
"echo-presence:orders,OrderShipped" => 'notifyNewOrder',
"echo-presence:orders,here" => 'notifyNewOrder',
"echo-presence:orders,joining" => 'notifyNewOrder',
"echo-presence:orders,leaving" => 'notifyNewOrder',
];
}
 
public function notifyNewOrder()
{
$this->showNewOrderNotification = true;
}
}