主题
wire:loading
加载指示器是构建良好用户界面的重要组成部分。它们在向服务器发送请求时向用户提供视觉反馈,让用户知道他们正在等待一个过程完成。
考虑使用 data-loading 选择器代替
虽然 wire:loading 非常适合简单的显示/隐藏场景,但 Livewire v4 引入了在触发网络请求的元素上自动添加 data-loading 属性的功能。这种方法通常更简单、更灵活——你可以直接使用 Tailwind 设置加载状态的样式,而无需 wire:target 指令,并且即使在向其他组件派发事件时也能无缝工作。了解更多关于 data-loading →
基本用法
Livewire 提供了一个简单但极其强大的语法来控制加载指示器:wire:loading。将 wire:loading 添加到任何元素将默认隐藏它(在 CSS 中使用 display: none),并在向服务器发送请求时显示它。
以下是一个 CreatePost 组件表单的基本示例,使用 wire:loading 来切换加载消息:
blade
<form wire:submit="save">
<!-- ... -->
<button type="submit">Save</button>
<div wire:loading>
Saving post...
</div>
</form>当用户按下"Save"时,"Saving post..." 消息将在执行"save"操作时显示在按钮下方。当从服务器接收到响应并被 Livewire 处理后,消息将消失。
移除元素
或者,你可以添加 .remove 来实现相反的效果,默认显示元素并在向服务器发送请求时隐藏它:
blade
<div wire:loading.remove>...</div>切换类
除了切换整个元素的可见性外,在向服务器发送请求时通过切换 CSS 类来更改现有元素的样式通常也很有用。此技术可用于更改背景颜色、降低不透明度、触发旋转动画等。
以下是一个使用 Tailwind 类 opacity-50 的简单示例,在提交表单时使"Save"按钮变淡:
blade
<button wire:loading.class="opacity-50">Save</button>与切换元素类似,你可以通过在 wire:loading 指令后添加 .remove 来执行相反的类操作。在下面的示例中,当按下"Save"按钮时,按钮的 bg-blue-500 类将被移除:
blade
<button class="bg-blue-500" wire:loading.class.remove="bg-blue-500">
Save
</button>切换属性
默认情况下,当表单提交时,Livewire 会自动禁用提交按钮,并在处理表单时为每个输入元素添加 readonly 属性。
然而,除了这个默认行为外,Livewire 还提供了 .attr 修饰符,允许你在元素上切换其他属性,或在表单外部的元素上切换属性:
blade
<button
type="button"
wire:click="remove"
wire:loading.attr="disabled"
>
Remove
</button>因为上面的按钮不是提交按钮,所以在按下时不会被 Livewire 的默认表单处理行为禁用。相反,我们手动添加了 wire:loading.attr="disabled" 来实现此行为。
定向特定操作
默认情况下,只要组件向服务器发出请求,wire:loading 就会被触发。
然而,在具有多个可以触发服务器请求的元素的组件中,你应该将加载指示器的范围缩小到单个操作。
例如,考虑以下"保存文章"表单。除了提交表单的"Save"按钮外,可能还有一个执行组件上"remove"操作的"Remove"按钮。
通过将 wire:target 添加到以下 wire:loading 元素,你可以指示 Livewire 只在点击"Remove"按钮时显示加载消息:
blade
<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>当按下上面的"Remove"按钮时,"Removing post..." 消息将显示给用户。然而,当按下"Save"按钮时,消息不会显示。
定向多个操作
你可能会遇到希望 wire:loading 对页面上的某些操作做出反应但不是全部操作的情况。在这些情况下,你可以将多个操作传递给 wire:target,用逗号分隔。例如:
blade
<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>现在加载指示器("Updating post...")只会在按下"Remove"或"Save"按钮时显示,而不会在 $title 字段发送到服务器时显示。
定向操作参数
在同一操作从页面上的多个位置以不同参数触发的情况下,你可以通过传入额外的参数来进一步将 wire:target 的范围缩小到特定操作。例如,考虑以下场景,页面上的每篇文章都有一个"Remove"按钮:
blade
<div v-pre>
@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",当点击页面上的任何按钮时,"Removing post..." 消息都会显示。
然而,因为我们向每个 wire:target 实例传递了唯一的参数,Livewire 只会在匹配的参数传递给"remove"操作时显示加载消息。
定向属性更新
Livewire 还允许你通过将属性名称传递给 wire:target 指令来定向特定的组件属性更新。
考虑以下示例,其中名为 username 的表单输入使用 wire:model.live 在用户输入时进行实时验证:
blade
<form wire:submit="save" v-pre>
<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>当用户在输入字段中输入时,"Checking availability..." 消息将在服务器更新新用户名时显示。
排除特定加载目标
有时你可能希望为每个 Livewire 请求显示加载指示器,_除了_特定的属性或操作。在这些情况下,你可以像这样使用 wire:target.except 修饰符:
blade
<div wire:loading wire:target.except="download">...</div>上面的加载指示器现在将为组件上的每个 Livewire 更新请求显示,除了"download"操作。
自定义 CSS display 属性
当 wire:loading 添加到元素时,Livewire 会更新元素的 CSS display 属性来显示和隐藏元素。默认情况下,Livewire 使用 none 来隐藏,使用 inline-block 来显示。
如果你正在切换一个使用 inline-block 以外的 display 值的元素,比如以下示例中的 flex,你可以在 wire:loading 后添加 .flex:
blade
<div class="flex" wire:loading.flex>...</div>以下是可用 display 值的完整列表:
blade
<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:
blade
<div wire:loading.delay>...</div>上面的元素只会在请求超过 200 毫秒时出现。如果请求在此之前完成,用户将永远不会看到指示器。
要自定义延迟加载指示器的时间量,你可以使用 Livewire 提供的便捷间隔别名之一:
blade
<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 -->使用 data-loading 样式
Livewire 自动为任何触发网络请求的元素添加 data-loading 属性。这允许你直接使用 CSS 或 Tailwind 设置加载状态的样式,而无需使用 wire:loading 指令。
使用 Tailwind 的 data 属性变体
你可以使用 Tailwind 的 data-loading 变体在元素加载时应用样式:
blade
<button
wire:click="save"
class="data-loading:opacity-50 data-loading:pointer-events-none"
>
Save Changes
</button>当点击按钮并且请求正在进行中时,它将自动变为半透明且不可点击。
使用 CSS
如果你没有使用 Tailwind,你可以使用标准 CSS 定位 data-loading 属性:
css
[data-loading] {
opacity: 0.5;
pointer-events: none;
}
button[data-loading] {
background-color: #ccc;
cursor: wait;
}样式化父元素和子元素
你可以使用 has-data-loading: 变体在子元素具有 data-loading 时设置父元素的样式:
blade
<div class="has-data-loading:opacity-50">
<button wire:click="save">Save</button>
</div>或者使用 in-data-loading: 变体从具有 data-loading 的父元素设置子元素的样式:
blade
<button wire:click="save">
<span class="in-data-loading:hidden">Save</span>
<span class="hidden in-data-loading:block">Saving...</span>
</button>另请参阅
参考
blade
wire:loading
wire:target="action"
wire:target="property"
wire:target.except="action"修饰符
| 修饰符 | 描述 |
|---|---|
.remove | 默认显示元素,加载时隐藏 |
.class="class-name" | 加载时添加 CSS 类 |
.class.remove="class-name" | 加载时移除 CSS 类 |
.attr="attribute" | 加载时添加 HTML 属性 |
.delay | 延迟 200ms 显示指示器 |
.delay.shortest | 延迟 50ms |
.delay.shorter | 延迟 100ms |
.delay.short | 延迟 150ms |
.delay.long | 延迟 300ms |
.delay.longer | 延迟 500ms |
.delay.longest | 延迟 1000ms |
.inline-flex | 使用 inline-flex display 值 |
.inline | 使用 inline display 值 |
.block | 使用 block display 值 |
.table | 使用 table display 值 |
.flex | 使用 flex display 值 |
.grid | 使用 grid display 值 |