AlpineJS
AlpineJS
在很多情况下,页面交互不能保证完整的服务器往返,例如切换模式。
对于这些情况,AlpineJS 是 Livewire 的完美伴侣。
它允许您以 declarative/reactive 的方式将 JavaScript 行为直接添加到标记中,这应该与 VueJS 非常相似(如果这是您惯用的方式)。
在Livewire中使用Alpine
Livewire 开箱即用地支持 Alpine,并且努力使组合尽可能平滑。
注意:必须安装Alpine才能使用它。 请查看Alpine repo 以获取安装说明。
这是在 Livewire 组件的视图内使用 AlpineJS 进行“下拉”功能的示例。
<div>
...
<div x-data="{ open: false }">
<button @click="open = true">Show More...</button>
<ul x-show="open" @click.away="open = false">
<li><button wire:click="archive">Archive</button></li>
<li><button wire:click="delete">Delete</button></li>
</ul>
</div>
</div>
提取可重复使用的 blade 组件
如果您还不习惯使用每种工具,那么混合使用两种语法可能会有些混乱。
因此,在可能的情况下,您应该将 Alpine 提取到可重复使用的 Blade 组件中,以便在 Livewire(以及应用程序中的任何位置)中使用。
这是一个示例(使用Laravel 7 Blade组件标签语法)。
Livewire 视图:
<div>
...
<x:dropdown>
<x-slot name="trigger">
<button>Show More...</button>
</x-slot>
<ul>
<li><button wire:click="archive">Archive</button></li>
<li><button wire:click="delete">Delete</button></li>
</ul>
</x:dropdown>
</div>
可重用的“下拉”blade组件:
<div x-data="{ open: false }">
<span @click="open = true">{{ $trigger }}</span>
<div x-show="open" @click.away="open = false">
{{ $slot }}
</div>
</div>
现在,Livewire和Alpine语法完全分开,并且您具有可重用的Blade组件,可以与其他组件一起使用。
创建一个DatePicker组件
Livewire中JavaScript的一个常见用例是自定义表单输入。 日期选择器,颜色选择器等之类的东西对于您的应用程序通常是必不可少的。
通过使用上面相同的模式(并添加一些额外的调整),我们可以利用Alpine轻松地与这些类型的JavaScript组件进行交互。
让我们创建一个名为date-picker
的可重复使用的 Blade 组件,我们可以使用它使用 wire:model
将某些数据绑定到Livewire中。
这是我们将如何使用它:
<form wire:submit.prevent="schedule">
<label for="title">Event Title</label>
<input wire:model="title" id="title" type="text">
<label for="date">Event Date</label>
<x:date-picker wire:model="date" id="date"/>
<button>Schedule Event</button>
</form>
对于此组件,我们将使用 Pikaday 库。
根据文档,软件包(引入静态资源之后)的最基本用法如下所示:
<input type="text" id="datepicker">
<script>
new Pikaday({ field: document.getElementById('datepicker') })
</script>
您只需要一个 元素,Pikaday 将为您添加所有额外的日期选择器行为。
现在,让我们看看如何为该库编写可重复使用的Blade组件。
date-picker
可重用blade组件:
<input
x-data
x-ref="input"
x-init="new Pikaday({ field: $refs.input })"
type="text"
{{ $attributes }}
>
注意:{{$attributes}} 表达式是 Laravel 7 及更高版本中的一种机制,用于转发在组件标签上声明的额外HTML属性。
转发 wire:model
input
事件
在幕后,每次在元素上或元素下分配 input 事件时,wire:model
都会添加一个事件侦听器以更新属性。 在 Livewire 和 Alpine 之间进行通信的另一种方法是使用 Alpine 调度一个 input 事件,并在其上具有 wire:model 元素的元素内或元素上的一些数据。
让我们创建一个人为设计的示例,其中当用户单击一个按钮时,名为 $foo
的属性设置为bar
,而当用户单击另一个按钮时,将 $foo
设置为baz
。
在Livewire组件的视图内:
<div>
<div wire:model="foo">
<button x-data @click="$dispatch('input', 'bar')">Set to "bar"</button>
<button x-data @click="$dispatch('input', 'baz')">Set to "baz"</button>
</div>
</div>
一个更真实的示例将创建一个“颜色选择器” Blade组件,该组件可能会在Livewire组件中使用。
Color-picker 组件用法:
<div>
<x:color-picker wire:model="color"/>
</div>
对于组件定义,我们将使用名为Vanilla Picker的第三方颜色选择器库。
本示例假定您已将其加载到页面上。
Color-Picker blade 组件定义(未注释):
<div
x-data="{ color: '#ffffff' }"
x-init="
picker = new Picker($refs.button);
picker.onDone = rawColor => {
color = rawColor.hex;
$dispatch('input', color)
}
"
wire:ignore
{{ $attributes }}
>
<span x-text="color" :style="`background: ${color}`"></span>
<button x-ref="button">Change</button>
</div>
Color-picker blade 组件定义 (注释):
<div
x-data="{ color: '#ffffff' }"
x-init="
// 单击“更改”按钮时,连线以显示选择器。
picker = new Picker($refs.button);
// 每次选择新颜色时都运行此回调。
picker.onDone = rawColor => {
// 设置Alpine的“颜色”属性。
color = rawColor.hex;
// 分配 color属性供 'wire:model' 使用。
$dispatch('input', color)
}
"
// Vanilla Picker 会将自己的DOM附加到此元素中,因此我们需要添加 `wire:ignore` 来告诉 Livewire 跳过DOM区分。
wire:ignore
// 转发添加到组件标签的所有属性,例如 `wire:model = color`
{{ $attributes }}
>
<!-- 在将背景色设置为所选颜色的情况下显示当前颜色值。 -->
<span x-text="color" :style="`background: ${color}`"></span>
<!-- 单击此按钮时,将显示颜色选择器对话框。-->
<button x-ref="button">Change</button>
</div>
忽略DOM更改(使用wire:ignore
)
幸运的是,像 Pikaday 这样的库在页面末尾添加了额外的 DOM。 许多其他库在初始化后便会立即操作 DOM,并在与它们交互时继续对 DOM 进行更改。
发生这种情况时,Livewire 很难跟踪要在组件更新中保留哪些DOM操作以及要丢弃哪些DOM操作。
要告诉Livewire 忽略组件中HTML子集的更改,可以添加 wire:ignore
指令。
Select2 库是接管DOM一部分的那些库之一(它用大量的自定义标记替换了 <select>
标签)。
这是一个在Livewire组件中使用Select2库的示例,以演示 wire:ignore
的用法。
<div>
<div wire:ignore>
<select class="select2" name="state">
<option value="AL">Alabama</option>
<option value="WY">Wyoming</option>
</select>
<!-- Select2 will insert it's DOM here. -->
</div>
</div>
@push('scripts')
<script>
$(document).ready(function() {
$('.select2').select2();
});
</script>
@endpush
另外,请注意,有时忽略元素的更改(而不是其子元素)会很有用。 在这种情况下,您可以将 self
修饰符添加到 wire:ignore
指令中,例如:wire:ignore.self
.
在Livewire和JavaScript之间进行通信
浏览器页面上加载的每个Livewire组件都具有唯一的ID和相应的JavaScript对象。
您可以使用以下语法检索此JavaScript对象:let component = window.livewire.find('some-component-id')
现在有了组件对象,您实际上可以从JavaScript以编程方式与其进行交互。
例如,给定以下Livewire组件:
CreatePost
use Livewire\Component;
class CreatePost extends Component
{
public $title = '';
public function create()
{
Post::create(['title' => $this->title]);
}
public function render()
{
return view('livewire.create-post');
}
}
create-post.blade.php
<form wire:submit.prevent="create">
<input wire:model="title" type="text">
<button>Create Post</button>
</form>
如果您偶然知道在浏览器中加载该组件时分配给该组件的唯一组件ID,则可以在DevTools中运行以下命令(或从页面上的任何JavaScript运行):
<script>
let component = window.livewire.find('the-unique-component-id')
var title = component.get('title')
// 获取 `public $title` 组件属性的当前值。
// 默认为“”,因此“ title”最初将设置为空字符串。
component.set('title', 'Some Title')
// 将 public $title 组件属性设置为 “ Some Title”
// 您实际上会在页面的输入字段中看到“Some Title”。
// 对于Livewire,调用此方法与实际在输入字段中键入之间没有区别。
component.call('create')
// 这将完全在组件上调用“ create”方法,就好像您在窗体上单击物理按钮一样。
</script>
如果可以跟随,那么您应该能够在这里看到潜力。 该API允许您通过JavaScript以编程方式与Livewire组件进行交互。 这种模式释放了各种潜力。
您可能想知道,“但是如何获得唯一的组件ID?”。 好了,您可以检查源代码并查看组件根元素上的wire:id
属性。 或者,您可以从Livewire组件的视图内部使用以下非常方便的语法:
<div>
<input x-data @input.keydown.enter="@this.set('foo', 'bar')">
</div>
如果您遵循的话,Livewire会有一个名为@this
的Blade指令,它是window.livewire.find('...')
的别名。 该指令使从 JavaScript(特别是AlpineJS表达式)与当前Livewire组件的通讯变得非常容易。
如果您要在浏览器中检查渲染页面的源,则输入元素将如下所示:
<input x-data @input.keydown.enter="window.livewire.find('unique-id').set('foo', 'bar')">
如您所见,Livewire和Alpine组合非常强大且富有表现力。