组件
Livewire 组件本质上是带有属性和方法的 PHP 类,可直接从 Blade 模板中调用。这种强大的组合让你能以远低于现代 JavaScript 方案的工作量和复杂度,打造全栈交互界面。
本指南涵盖创建、渲染与组织 Livewire 组件所需的全部知识。你将了解可用的不同组件格式(单文件、多文件与基于类),如何在组件间传递数据,以及如何把组件用作完整页面。
创建组件
你可以使用 make:livewire Artisan 命令创建组件:
php artisan make:livewire post.create这会在以下位置创建单文件组件:
resources/views/components/post/⚡create.blade.php
<?php
use Livewire\Component;
new class extends Component {
public $title = '';
public function save()
{
// Save logic here...
}
};
?>
<div>
<input wire:model="title" type="text">
<button wire:click="save">Save Post</button>
</div>INFO
为什么文件名里有 ⚡ 表情?
你可能对文件名中的闪电符号感到好奇。这个小细节有实际用途:它让 Livewire 组件在编辑器的文件树和搜索结果中一眼可辨。因为它是 Unicode 字符,在 Windows、macOS、Linux、Git 以及生产服务器等所有平台上都能无缝工作。
表情符号完全可选;若觉得不习惯,可以在 config/livewire.php 中彻底关闭:
'make_command' => [
'emoji' => false,
],TIP
更偏好 v3 约定?
若你更喜欢 v3 的基于类的组件,可以在 config/livewire.php 中用两行配置恢复以前的默认行为:
'make_command' => [
'type' => 'class',
'emoji' => false,
],创建页面组件
创建将用作完整页面的组件时,使用 pages:: 命名空间,把它们组织到专用目录中:
php artisan make:livewire pages::post.create这会在 resources/views/pages/post/⚡create.blade.php 创建组件。这种组织方式能清楚区分哪些是页面组件、哪些是可复用的 UI 组件。
多文件组件
随着组件或项目变大,你可能觉得单文件方式受限。Livewire 提供多文件方案,把组件拆成多个文件,便于组织和获得更好的 IDE 支持。
要创建多文件组件,传入 --mfc 标志:
php artisan make:livewire post.create --mfc这会创建一个目录,并把所有相关文件放在一起:
resources/views/components/post/⚡create/
├── create.php # PHP class
├── create.blade.php # Blade template
├── create.js # JavaScript (optional)
├── create.css # Scoped styles (optional)
├── create.global.css # Global styles (optional)
└── create.test.php # Pest test (optional, with --test flag)命令选项
make:livewire 命令接受以下选项:
| Option | 说明 |
|---|---|
--sfc | 创建单文件组件(默认) |
--mfc | 创建多文件组件 |
--class | 创建基于类的组件 |
--type=sfc|mfc|class | 显式指定组件类型 |
--emoji=true|false | 覆盖本次命令的配置项 emoji 设置 |
--test | 包含 Pest 测试文件 |
--js | 包含 JavaScript 文件(仅多文件组件) |
--css | 包含 CSS 文件(仅多文件组件) |
在格式之间转换
Livewire 提供 livewire:convert 命令,可在单文件与多文件格式之间无缝转换组件。
自动检测并转换:
php artisan livewire:convert post.create
# Single-file → Multi-file (or vice versa)显式转换为多文件:
php artisan livewire:convert post.create --mfc这会解析你的单文件组件,创建目录结构,拆分文件,并删除原文件。
显式转换为单文件:
php artisan livewire:convert post.create --sfc这会把所有文件合并回单个文件,并删除该目录。
WARNING
转换为单文件时会删除测试文件
若多文件组件带有测试文件,转换前会提示你确认,因为单文件格式无法保留测试文件。
何时使用各格式
单文件组件(默认):
- 适合大多数组件
- 把相关代码放在一起
- 一眼就能看懂
- 适合中小型组件
多文件组件:
- 更适合大型、复杂的组件
- 更好的 IDE 支持与导航
- 组件含有大量 JavaScript 时职责更清晰
基于类的组件:
- 对来自 Livewire v2/v3 的开发者更熟悉
- 传统的 Laravel 关注点分离
- 更适合已有既定约定的团队
- 参见下方的基于类的组件
渲染组件
你可以在任意 Blade 模板中使用 <livewire:component-name /> 语法引入 Livewire 组件:
<livewire:component-name />若组件位于子目录中,可用点号(.)表示:
resources/views/components/post/⚡create.blade.php
<livewire:post.create />对于带命名空间的组件——例如 pages::——使用命名空间前缀:
<livewire:pages::post.create />文件路径如何映射到组件名
无论使用哪种格式(单文件、多文件或基于类),在 Blade 标签和路由中使用的组件名始终相同。⚡ 表情前缀和文件结构会自动剥离:
| 格式 | 文件路径 | 组件名 |
|---|---|---|
| 单文件 | resources/views/components/post/⚡create.blade.php | post.create |
| 多文件 | resources/views/components/post/⚡create/create.php | post.create |
| 基于类 | app/Livewire/Post/Create.php | post.create |
| 单文件(命名空间) | resources/views/pages/post/⚡create.blade.php | pages::post.create |
| 多文件(命名空间) | resources/views/pages/post/⚡create/create.php | pages::post.create |
这意味着你可以在格式之间切换,而无需修改任何 Blade 模板或路由。
传递 props
要把数据传入 Livewire 组件,可以在组件标签上使用 prop 属性:
<livewire:post.create title="Initial Title" />对于动态值或变量,在属性前加冒号:
<livewire:post.create :title="$initialTitle" />传入组件的数据通过 mount() 方法接收:
<?php
use Livewire\Component;
new class extends Component {
public $title;
public function mount($title = null)
{
$this->title = $title;
}
// ...
};你可以把 mount() 方法看作类构造函数。它在组件初始化时运行,但不会在同一页面会话的后续请求中再次运行。关于 mount() 及其他有用的生命周期钩子,详见生命周期文档。
为减少样板代码,你可以省略 mount() 方法,Livewire 会自动为名称与传入值匹配的属性赋值:
<?php
use Livewire\Component;
new class extends Component {
public $title; // Automatically set from prop
// ...
};WARNING
这些属性默认不是响应式的
若外层的 :title="$initialValue" 在首次页面加载后发生变化,$title 属性不会自动更新。这是使用 Livewire 时常见的困惑点,尤其是用过 Vue 或 React 等 JavaScript 框架的开发者,往往会假设这些参数像那些框架中的「响应式 props」一样工作。不过不用担心,Livewire 允许你选择启用响应式 props。
将路由参数作为 props 传递
把组件用作页面时,可以直接把路由参数传给组件。路由参数会自动传给 mount() 方法:
Route::livewire('/posts/{id}', 'pages::post.show');<?php // resources/views/pages/post/⚡show.blade.php
use Livewire\Component;
new class extends Component {
public $postId;
public function mount($id)
{
$this->postId = $id;
}
};Livewire 也支持 Laravel 的路由模型绑定:
Route::livewire('/posts/{post}', 'pages::post.show');<?php // resources/views/pages/post/⚡show.blade.php
use App\Models\Post;
use Livewire\Component;
new class extends Component {
public Post $post; // Automatically bound from route
// No mount() needed - Livewire handles it automatically
};页面组件
可以使用 Route::livewire() 把组件直接路由为完整页面。这是 Livewire 最强大的特性之一,让你无需传统控制器就能构建整页。
Route::livewire('/posts/create', 'pages::post.create');当用户访问 /posts/create 时,Livewire 会在应用的布局文件中渲染 pages::post.create 组件。
页面组件与普通组件工作方式相同,但会作为完整页面渲染,并可使用:
- 自定义布局
- 页面标题
- 路由参数与模型绑定
- 布局的具名插槽
关于页面组件的完整说明(含布局、标题与高级路由),参见页面文档。
在视图中访问数据
Livewire 提供多种方式把数据传给组件的 Blade 视图。每种方式在性能与安全性上各有特点。
组件属性
最简单的方式是使用公共属性,它们会自动在 Blade 模板中可用:
<?php
use Livewire\Component;
new class extends Component {
public $title = 'My Post';
};<div>
<h1>{{ $title }}</h1>
</div>受保护属性必须通过 $this-> 访问:
public $title = 'My Post'; // Available as {{ $title }}
protected $apiKey = 'secret-key'; // Available as {{ $this->apiKey }}INFO
受保护属性不会发送到客户端
与公共属性不同,受保护属性绝不会发送到前端,也无法被用户篡改,因此适合存放敏感数据。不过它们不会在请求之间持久化,这限制了它们在多数 Livewire 场景中的用处。最适合用于属性声明中定义的、你不希望暴露到客户端的静态值。
关于属性的完整说明(含持久化行为与高级特性),参见属性文档。
计算属性
计算属性是行为类似带缓存属性的方法。非常适合数据库查询等开销较大的操作:
use Livewire\Attributes\Computed;
#[Computed]
public function posts()
{
return Post::with('author')->latest()->get();
}<div>
@foreach ($this->posts as $post)
<article wire:key="{{ $post->id }}">{{ $post->title }}</article>
@endforeach
</div>注意 $this-> 前缀——这会告诉 Livewire 调用该方法,并仅在当前请求内缓存结果(不会跨请求)。更多细节见属性文档中的计算属性章节。
从 render() 传递数据
与控制器类似,你可以使用 render() 方法直接把数据传给视图:
public function render()
{
return $this->view([
'author' => Auth::user(),
'currentTime' => now(),
]);
}请注意:render() 会在每次组件更新时运行,因此除非每次更新都需要最新数据,否则应避免在这里做开销大的操作。
组织组件
虽然 Livewire 会自动发现默认 resources/views/components/ 目录中的组件,但你可以自定义 Livewire 查找组件的位置,并用命名空间来组织它们。
组件命名空间
组件命名空间让你把组件组织到专用目录中,并用简洁的引用语法访问。
默认情况下,Livewire 提供两个命名空间:
pages::— 指向resources/views/pages/layouts::— 指向resources/views/layouts/
你可以在 config/livewire.php 中定义更多命名空间:
'component_namespaces' => [
'layouts' => resource_path('views/layouts'),
'pages' => resource_path('views/pages'),
'admin' => resource_path('views/admin'), // Custom namespace
'widgets' => resource_path('views/widgets'), // Another custom namespace
],然后在创建、渲染和路由时使用它们:
php artisan make:livewire admin::users-table<livewire:admin::users-table />Route::livewire('/admin/users', 'admin::users-table');额外的组件位置
若希望 Livewire 在默认目录之外的更多目录中发现组件,可在 config/livewire.php 中配置:
'component_locations' => [
resource_path('views/components'),
resource_path('views/admin/components'),
resource_path('views/widgets'),
],现在 Livewire 会自动发现所有这些目录中的组件。
程序化注册
对于更动态的场景(如扩展包开发或运行时配置),可以在服务提供者中以编程方式注册组件、位置和命名空间:
注册单个组件:
use Livewire\Livewire;
// In a service provider's boot() method (e.g., App\Providers\AppServiceProvider)
Livewire::addComponent(
name: 'custom-button',
viewPath: resource_path('views/ui/button.blade.php')
);注册组件目录:
Livewire::addLocation(
viewPath: resource_path('views/admin/components')
);注册命名空间:
Livewire::addNamespace(
namespace: 'ui',
viewPath: resource_path('views/ui')
);当你需要按条件注册组件,或在构建提供 Livewire 组件的 Laravel 扩展包时,这种方式很有用。
注册基于类的组件
对于基于类的组件,使用相同的方法,但用 class 参数代替 path:
use Livewire\Livewire;
// In a service provider's boot() method (e.g., App\Providers\AppServiceProvider)
// Register an individual class-based component
Livewire::addComponent(
name: 'todos',
class: \App\Livewire\Todos::class
);
// Register a location for class-based components
Livewire::addLocation(
classNamespace: 'App\\Admin\\Livewire'
);
// Create a namespace for class-based components
Livewire::addNamespace(
namespace: 'admin',
classNamespace: 'App\\Admin\\Livewire',
classPath: app_path('Admin/Livewire'),
classViewPath: resource_path('views/admin/livewire')
);基于类的组件
对于从 Livewire v3 迁移的团队,或偏好更传统 Laravel 结构的开发者,Livewire 完全支持基于类的组件。这种方式把 PHP 类和 Blade 视图拆到各自约定位置的不同文件中。
创建基于类的组件
php artisan make:livewire CreatePost --class这会创建两个独立文件:
app/Livewire/CreatePost.php
<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public function render()
{
return view('livewire.create-post');
}
}resources/views/livewire/create-post.blade.php
<div>
{{-- ... --}}
</div>何时使用基于类的组件
在以下情况使用基于类的组件:
- 从 Livewire v2/v3 迁移
- 团队更偏好传统文件结构
- 已有围绕基于类架构的既定约定
在以下情况使用单文件或多文件组件:
- 开始新的 Livewire v4 项目
- 希望组件代码更好地同置(colocation)
- 希望采用最新的 Livewire 约定
配置默认组件类型
若希望默认使用基于类的组件,在 config/livewire.php 中配置:
'make_command' => [
'type' => 'class',
],自定义组件 stub
你可以自定义 Livewire 用于生成新组件的文件(或 stub),运行:
php artisan livewire:stubs这会在应用中创建可修改的 stub 文件:
单文件组件 stub:
stubs/livewire-sfc.stub— 单文件组件
多文件组件 stub:
stubs/livewire-mfc-class.stub— 多文件组件的 PHP 类stubs/livewire-mfc-view.stub— 多文件组件的 Blade 视图stubs/livewire-mfc-js.stub— 多文件组件的 JavaScriptstubs/livewire-mfc-test.stub— 多文件组件的 Pest 测试
基于类的组件 stub:
stubs/livewire.stub— 基于类组件的 PHP 类stubs/livewire.view.stub— 基于类组件的 Blade 视图
其他 stub:
stubs/livewire.attribute.stub— Attribute 类stubs/livewire.form.stub— Form 类
发布后,Livewire 在生成新组件时会自动使用你的自定义 stub。
排错
找不到组件
症状: 出现类似 "Component [post.create] not found" 或 "Unable to find component" 的错误信息
解决办法:
- 确认组件文件存在于预期路径
- 检查视图中的组件名是否与文件结构匹配(子目录用点号)
- 对于带命名空间的组件,确保命名空间已在
config/livewire.php中定义,或已在服务提供者中手动注册 - 尝试清除视图缓存:
php artisan view:clear
组件显示空白或不渲染
常见原因:
- Blade 模板缺少根元素(Livewire 要求恰好一个根元素)
- 组件 PHP 部分存在语法错误
- 查看 Laravel 日志获取详细错误信息
类名冲突
症状: 使用单文件组件时出现关于重复类名的错误
解决办法: 若在不同目录中有多个同名单文件组件,就可能出现此问题。可以:
- 将其中一个组件重命名为唯一名称
- 为其中一个目录添加命名空间,以更清晰地隔离