wire:loading
加载指示器是制作良好用户界面的重要组成部分。当向服务器发出请求时,它们向用户提供视觉反馈,以便他们知道正在等待某个进程完成。
基本用法
Livewire 提供了一个简单但极其强大的语法来控制加载指示器:wire:loading
。将 wire:loading
添加到任何元素都将默认隐藏它(在 CSS 中使用 display: none
),并在向服务器发送请求时显示它。
下面是一个 CreatePost
组件表单的基本示例,其中使用 wire:loading
切换加载消息
<form wire:submit="save"> <!-- ... --> <button type="submit">Save</button> <div wire:loading> Saving post... </div></form>
当用户按“保存”时,“正在保存帖子...”消息将出现在按钮下方,同时执行“保存”操作。当从服务器收到响应并由 Livewire 处理后,该消息将消失。
移除元素
或者,你可以附加 .remove
以获得相反的效果,默认显示元素并在向服务器发出请求期间隐藏它
<div wire:loading.remove>...</div>
切换类
除了切换整个元素的可见性之外,在向服务器发出请求期间通过打开和关闭 CSS 类来更改现有元素的样式通常很有用。此技术可用于更改背景颜色、降低不透明度、触发旋转动画等。
下面是一个使用 Tailwind 类 opacity-50
的简单示例,在提交表单时使“保存”按钮变淡
<button wire:loading.class="opacity-50">Save</button>
与切换元素类似,你可以通过将 .remove
附加到 wire:loading
指令来执行反向类操作。在下面的示例中,当按下“保存”按钮时,按钮的 bg-blue-500
类将被移除
<button class="bg-blue-500" wire:loading.class.remove="bg-blue-500"> Save</button>
切换属性
默认情况下,当提交表单时,Livewire 将自动禁用提交按钮,并在表单被处理时向每个输入元素添加 readonly
属性。
然而,除了这种默认行为之外,Livewire 还提供了 .attr
修饰符,允许你在元素上切换其他属性或切换表单外部元素上的属性
<button type="button" wire:click="remove" wire:loading.attr="disabled"> Remove</button>
由于上面的按钮不是提交按钮,因此在按下时不会被 Livewire 的默认表单处理行为禁用。相反,我们手动添加了 wire:loading.attr="disabled"
来实现此行为。
针对特定操作
默认情况下,每当组件向服务器发出请求时,都会触发 wire:loading
。
然而,在具有多个可以触发服务器请求的元素的组件中,你应该将加载指示器缩小到单个操作。
例如,考虑以下“保存帖子”表单。除了提交表单的“保存”按钮之外,还可能有一个“移除”按钮,对组件执行“移除”操作。
通过将 wire:target
添加到以下 wire:loading
元素,你可以指示 Livewire 仅在单击“移除”按钮时显示加载消息
<form wire:submit="save"> <!-- ... --> <button type="submit">Save</button> <button type="button" wire:click="remove">Remove</button> <div wire:loading wire:target="remove"> Removing post... </div></form>
当按下上面的“移除”按钮时,“正在移除帖子...”消息将显示给用户。但是,当按下“保存”按钮时,不会显示该消息。
针对多个操作
你可能会发现自己处于希望 wire:loading
对页面上的某些操作(但不是全部)做出反应的情况。在这些情况下,你可以将多个操作以逗号分隔传递到 wire:target
。例如
<form wire:submit="save"> <input type="text" wire:model.blur="title"> <!-- ... --> <button type="submit">Save</button> <button type="button" wire:click="remove">Remove</button> <div wire:loading wire:target="save, remove"> Updating post... </div></form>
现在,只有在按下“移除”或“保存”按钮时才会显示加载指示器(“正在更新帖子...”),而不会在将 $title
字段发送到服务器时显示。
针对操作参数
在从页面上的多个地方使用不同参数触发相同操作的情况下,你可以通过传入其他参数将 wire:target
进一步限定到特定操作。例如,考虑以下场景,其中页面上每个帖子都有一个“移除”按钮
<div> @foreach ($posts as $post) <div wire:key="{{ $post->id }}"> <h2>{{ $post->title }}</h2> <button wire:click="remove({{ $post->id }})">Remove</button> <div wire:loading wire:target="remove({{ $post->id }})"> Removing post... </div> </div> @endforeach</div>
如果不将 {{ $post->id }}
传递给 wire:target="remove"
,则在单击页面上的任何按钮时都会显示“正在删除帖子...”消息。
但是,由于我们正在向 wire:target
的每个实例传递唯一参数,因此 Livewire 仅在将匹配参数传递给“remove”操作时才会显示加载消息。
目前,Livewire 仅支持通过单个方法/参数对来定位加载指示器。例如,支持 wire:target="remove(1)"
,但 wire:target="remove(1), add(1)"
不支持。
定位属性更新
Livewire 还允许你通过将属性名称传递给 wire:target
指令来定位特定的组件属性更新。
考虑以下示例,其中名为 username
的表单输入使用 wire:model.live
进行实时验证,因为用户正在输入
<form wire:submit="save"> <input type="text" wire:model.live="username"> @error('username') <span>{{ $message }}</span> @enderror <div wire:loading wire:target="username"> Checking availability of username... </div> <!-- ... --></form>
当服务器使用新用户名更新时,当用户在输入字段中输入时,将显示“正在检查可用性...”消息。
排除特定加载目标
有时你可能希望为每个 Livewire 请求显示加载指示器,除了特定的属性或操作。在这些情况下,你可以像这样使用 wire:target.except
修饰符
<div wire:loading wire:target.except="download">...</div>
上面的加载指示器现在将显示在组件上的每个 Livewire 更新请求中,除了“download”操作。
自定义 CSS display 属性
当将 wire:loading
添加到元素时,Livewire 会更新元素的 CSS display
属性以显示和隐藏元素。默认情况下,Livewire 使用 none
来隐藏和 inline-block
来显示。
如果你正在切换使用 inline-block
以外的显示值的元素,例如以下示例中的 flex
,则可以将 .flex
附加到 wire:loading
<div class="flex" wire:loading.flex>...</div>
以下是可用显示值的完整列表
<div wire:loading.inline-flex>...</div><div wire:loading.inline>...</div><div wire:loading.block>...</div><div wire:loading.table>...</div><div wire:loading.flex>...</div><div wire:loading.grid>...</div>
延迟加载指示器
在快速连接上,更新通常发生得如此之快,以至于加载指示器在被删除之前仅在屏幕上短暂闪烁。在这些情况下,指示器更像是一种干扰,而不是一种有用的帮助。
出于此原因,Livewire 提供了一个 .delay
修饰符来延迟指示器的显示。例如,如果你像这样向元素添加 wire:loading.delay
<div wire:loading.delay>...</div>
只有当请求花费超过 200 毫秒时,才会显示上述元素。如果在此之前请求完成,用户将永远看不到指示器。
要自定义延迟加载指示器的时间量,你可以使用 Livewire 的一个有用的间隔别名
<div wire:loading.delay.shortest>...</div> <!-- 50ms --><div wire:loading.delay.shorter>...</div> <!-- 100ms --><div wire:loading.delay.short>...</div> <!-- 150ms --><div wire:loading.delay>...</div> <!-- 200ms --><div wire:loading.delay.long>...</div> <!-- 300ms --><div wire:loading.delay.longer>...</div> <!-- 500ms --><div wire:loading.delay.longest>...</div> <!-- 1000ms -->