什么是 Livewire
在 Laravel 里做动态 UI 时,过去只能搭配 Vue.js、React 这样的 JavaScript 框架,或者自己写 AJAX 请求。
Livewire 就是为解决这个问题而生的 Laravel 包。只用 PHP 和 Blade 就能构建响应式 UI。表单实时校验、实时搜索、计数器等以前必须用 JavaScript 实现的功能,现在都可以用 PHP 完成。
Livewire 4 需要 Laravel 10 及以上、PHP 8.1 及以上。当前最新版本是 Livewire 4。
工作原理概览
一个 Livewire 组件由服务器端的 PHP 类和 Blade 模板组成。当用户点击按钮或在表单里输入时,Livewire 会在幕后发送 AJAX 请求、执行 PHP,并只把发生变化的部分反映到页面上。开发者不必关心这一机制,用纯 PHP 就能写出来。
在 Laravel 应用根目录执行:
composer require livewire/livewire
Laravel 会自动发现包,不需要额外配置。
创建布局文件
作为整页组件使用时,需要一个布局文件。用下面的 Artisan 命令生成:
php artisan livewire:layout
会生成 resources/views/layouts/app.blade.php。
<! DOCTYPE html >
< html lang = " {{ str_replace ('_', '-', app () -> getLocale ()) }} " >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > {{ $title ?? config ( 'app.name' ) }} </ title >
@vite ([ 'resources/css/app.css' , 'resources/js/app.js' ])
@livewireStyles
</ head >
< body >
{{ $slot }}
@livewireScripts
</ body >
</ html >
@livewireStyles 与 @livewireScripts 会自动加载 Livewire 与 Alpine.js 的资源。
第一个组件
有专门用来生成 Livewire 组件的 Artisan 命令。先做一个简单的计数器。
php artisan make:livewire Counter
这条命令会生成一个单文件组件 resources/views/components/⚡counter.blade.php。
文件名里的 ⚡ 用来一眼识别出 Livewire 组件,在编辑器里更醒目。不需要的话可以在配置里关掉。
把生成的文件按下面的方式改写:
<?php
use Livewire\ Component ;
new class extends Component {
public int $count = 0 ;
public function increment () : void
{
$this -> count ++ ;
}
public function decrement () : void
{
$this -> count -- ;
}
};
?>
< div >
< h1 > 计数: {{ $count }} </ h1 >
< button wire:click = "increment" > +1 </ button >
< button wire:click = "decrement" > -1 </ button >
</ div >
在 Blade 模板中通过普通的 Blade 组件语法嵌入它:
每次点击按钮,页面不用刷新就能更新计数。wire:click 就是取代 JavaScript,直接调用 PHP 方法的机制。
属性与动作
属性 —— wire:model
wire:model 指令可以把输入元素和组件的属性做双向绑定。
<?php
use Livewire\ Component ;
new class extends Component {
public string $name = '' ;
public string $email = '' ;
};
?>
< div >
< input type = "text" wire:model = "name" placeholder = "姓名" >
< input type = "email" wire:model = "email" placeholder = "邮箱" >
< p > 你好, {{ $name }} ( {{ $email }} ) </ p >
</ div >
默认情况下,wire:model 只在有动作发生时(比如表单提交)才和服务器同步。想每次输入都同步,加 .live 修饰符。
写法 行为 wire:model只在动作(如表单提交)时同步(默认) wire:model.live每次输入都发送请求 wire:model.blur失焦时同步(不发起请求) wire:model.live.blur失焦时发送请求
动作 —— wire:click、wire:submit
wire:click 把点击事件、wire:submit 把表单提交事件绑定到方法上。
<?php
use Livewire\ Component ;
use App\Models\ Task ;
new class extends Component {
public string $taskName = '' ;
public function addTask () : void
{
Task :: create ([ 'name' => $this -> taskName ]);
$this -> taskName = '' ;
}
public function render ()
{
return $this -> view ([
'tasks' => Task :: latest () -> get (),
]);
}
};
?>
< div >
< form wire:submit = "addTask" >
< input type = "text" wire:model = "taskName" placeholder = "任务名" >
< button type = "submit" > 添加 </ button >
</ form >
< ul >
@foreach ( $tasks as $task )
< li > {{ $task -> name }} </ li >
@endforeach
</ ul >
</ div >
实时校验
Livewire 4 可以通过 #[Validate] 属性直接为属性定义验证规则。
<?php
use Livewire\Attributes\ Validate ;
use Livewire\ Component ;
use App\Models\ Post ;
new class extends Component {
#[Validate('required|min:3')]
public string $title = '' ;
#[Validate('required|min:10')]
public string $content = '' ;
public function save () : void
{
$this -> validate ();
Post :: create ([
'title' => $this -> title ,
'content' => $this -> content ,
]);
$this -> reset ([ 'title' , 'content' ]);
session () -> flash ( 'message' , '文章已保存。' );
}
};
?>
< div >
@if ( session ( 'message' ))
< div > {{ session ( 'message' ) }} </ div >
@endif
< form wire:submit = "save" >
< div >
< input type = "text" wire:model.live.blur = "title" placeholder = "标题" >
@error ( 'title' ) < span style = "color: red;" > {{ $message }} </ span > @enderror
</ div >
< div >
< textarea wire:model.live.blur = "content" placeholder = "正文" ></ textarea >
@error ( 'content' ) < span style = "color: red;" > {{ $message }} </ span > @enderror
</ div >
< button type = "submit" > 保存 </ button >
</ form >
</ div >
被 #[Validate] 标注的属性每次更新时会自动执行校验。结合 wire:model.live.blur 可以做出“失焦瞬间显示错误信息”的实时校验体验。
$this->validate() 会在表单提交时一次性校验所有属性。推荐的做法是把它和 #[Validate] 的自动校验组合成两级校验。
生命周期钩子
Livewire 组件有几个生命周期钩子。
钩子 时机 mount()组件首次创建时(仅一次) boot()每次请求开始时(首次与后续请求都会调用) updating($property, $value)属性即将更新前 updated($property)属性更新后 rendering()视图渲染前 rendered()视图渲染后 dehydrate()每次请求结束时
mount() —— 初始化
mount() 用于组件初始化,类似构造函数。
<?php
use Illuminate\Support\Facades\ Auth ;
use Livewire\ Component ;
new class extends Component {
public string $name = '' ;
public string $email = '' ;
public function mount () : void
{
$this -> name = Auth :: user () -> name ;
$this -> email = Auth :: user () -> email ;
}
};
?>
< div >
< p > 姓名: {{ $name }} </ p >
< p > 邮箱: {{ $email }} </ p >
</ div >
updated() —— 属性变更后的处理
想在属性更新后加一段逻辑时用 updated()。想只针对特定属性时,把属性名放到方法名里。
<?php
use Livewire\ Component ;
new class extends Component {
public string $username = '' ;
public function updatedUsername () : void
{
$this -> username = strtolower ( $this -> username );
}
};
?>
< div >
< input type = "text" wire:model.live = "username" >
< p > 用户名: {{ $username }} </ p >
</ div >
每次输入都会自动转成小写。
与 Laravel 的集成
直接使用 Eloquent 模型
Livewire 的属性可以直接持有 Eloquent 模型。
<?php
use Livewire\Attributes\ Validate ;
use Livewire\ Component ;
use App\Models\ User ;
new class extends Component {
public User $user ;
public function mount ( User $user ) : void
{
$this -> user = $user ;
}
#[Validate('required|min:2')]
public string $name = '' ;
public function save () : void
{
$this -> validate ();
$this -> user -> update ([ 'name' => $this -> name ]);
session () -> flash ( 'message' , '资料已更新。' );
}
public function render ()
{
return $this -> view ();
}
};
?>
< div >
@if ( session ( 'message' ))
< div > {{ session ( 'message' ) }} </ div >
@endif
< form wire:submit = "save" >
< input type = "text" wire:model = "name" placeholder = "姓名" >
@error ( 'name' ) < span style = "color: red;" > {{ $message }} </ span > @enderror
< button type = "submit" > 更新 </ button >
</ form >
</ div >
表单对象
复杂表单可以拆到表单对象里,让组件更简洁。
php artisan livewire:form PostForm
namespace App\Livewire\Forms ;
use Livewire\Attributes\ Validate ;
use Livewire\ Form ;
use App\Models\ Post ;
class PostForm extends Form
{
#[ Validate ( 'required|min:3' )]
public string $title = '' ;
#[ Validate ( 'required|min:10' )]
public string $content = '' ;
public function store () : void
{
Post :: create ( $this -> only ([ 'title' , 'content' ]));
}
}
在组件里用这个表单对象。
<?php
use App\Livewire\Forms\ PostForm ;
use Livewire\ Component ;
new class extends Component {
public PostForm $form ;
public function save () : void
{
$this -> form -> validate ();
$this -> form -> store ();
$this -> form -> reset ();
session () -> flash ( 'message' , '已创建文章。' );
}
};
?>
< div >
< form wire:submit = "save" >
< input type = "text" wire:model = "form.title" placeholder = "标题" >
@error ( 'form.title' ) < span style = "color: red;" > {{ $message }} </ span > @enderror
< textarea wire:model = "form.content" placeholder = "正文" ></ textarea >
@error ( 'form.content' ) < span style = "color: red;" > {{ $message }} </ span > @enderror
< button type = "submit" > 发布 </ button >
</ form >
</ div >
Livewire 特别适合的用例:
用例 Livewire 能做什么 表单处理 实时校验、错误提示 数据列表 实时搜索、排序、分页 计数器 / 开关 页面不刷新的 UI 更新 管理后台 直接对接 Eloquent 完成 CRUD 向导型表单 步骤管理用 PHP 实现
只要你用过 Blade,今天就能开始用 Livewire。它最大的优势是:不必学习 JavaScript 框架就能构建交互式 UI。
需要接近 SPA 的复杂交互时 Inertia.js 更合适;但表单、后台、数据表格这类场景下,Livewire 通常能以更简洁的方式搞定。先从一个小组件开始试试吧。
Livewire 官方文档 Livewire 的完整功能(文件上传、分页、测试等)请查看官方文档。