主题
组件
Livewire 组件本质上是带有属性和方法的 PHP 类,可以直接从 Blade 模板中调用。这种强大的组合让你能够以现代 JavaScript 替代方案的一小部分精力和复杂度创建全栈交互式界面。
本指南涵盖了创建、渲染和组织 Livewire 组件所需了解的一切。你将学习可用的不同组件格式(单文件、多文件和基于类),如何在组件之间传递数据,以及如何将组件用作完整页面。
创建组件
你可以使用 make:livewire Artisan 命令创建组件:
shell
php artisan make:livewire post.create这会在以下位置创建一个单文件组件:
resources/views/components/post/⚡create.blade.php
blade
<?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>为什么使用 ⚡ emoji?
你可能想知道文件名中的闪电符号是什么意思。这个小细节有实际作用:它使 Livewire 组件在编辑器的文件树和搜索结果中立即可识别。由于它是 Unicode 字符,因此可以在所有平台上无缝工作 — Windows、macOS、Linux、Git 和你的生产服务器。
emoji 是完全可选的,如果你觉得不习惯,可以在 config/livewire.php 文件中完全禁用它:
php
'make_command' => [
'emoji' => false,
],创建页面组件
创建将用作完整页面的组件时,使用 pages:: 命名空间将它们组织在专用目录中:
shell
php artisan make:livewire pages::post.create这会在 resources/views/pages/post/⚡create.blade.php 创建组件。这种组织方式清楚地区分了哪些组件是页面,哪些是可重用的 UI 组件。
在下面的页面组件章节中了解更多关于将组件用作页面的信息。
多文件组件
随着组件或项目的增长,你可能会发现单文件方法的局限性。Livewire 提供了一种多文件替代方案,将组件拆分为单独的文件,以获得更好的组织和 IDE 支持。
要创建多文件组件,传递 --mfc 标志:
shell
php artisan make:livewire post.create --mfc这会创建一个包含所有相关文件的目录:
resources/views/components/⚡post.create/
├── post.create.php # PHP 类
├── post.create.blade.php # Blade 模板
├── post.create.js # JavaScript (可选,使用 --js 标志)
└── post.create.test.php # Pest 测试 (可选,使用 --test 标志)格式之间的转换
Livewire 提供了 livewire:convert 命令,可以在单文件和多文件格式之间无缝转换组件。
自动检测并转换:
shell
php artisan livewire:convert post.create
# 单文件 → 多文件 (或反之)显式转换为多文件:
shell
php artisan livewire:convert post.create --mfc这将解析你的单文件组件,创建目录结构,拆分文件,并删除原始文件。
显式转换为单文件:
shell
php artisan livewire:convert post.create --sfc这会将所有文件组合回单个文件并删除目录。
转换为单文件时会删除测试文件
如果你的多文件组件有测试文件,在转换之前会提示你确认,因为测试文件无法在单文件格式中保留。
何时使用每种格式
单文件组件(默认):
- 最适合大多数组件
- 将相关代码保持在一起
- 一目了然
- 非常适合小到中型组件
多文件组件:
- 更适合大型、复杂的组件
- 改进的 IDE 支持和导航
- 当组件有大量 JavaScript 时更清晰的分离
- 使用专用测试文件更容易测试
基于类的组件:
- 对来自 Livewire v2/v3 的开发者来说很熟悉
- 传统的 Laravel 关注点分离
- 更适合有既定惯例的团队
- 参见下面的基于类的组件
渲染组件
你可以使用 <livewire:component-name /> 语法在任何 Blade 模板中包含 Livewire 组件:
blade
<livewire:post.create />如果组件位于子目录中,可以使用点(.)字符来表示:
resources/views/components/post/⚡create.blade.php
blade
<livewire:post.create />对于页面组件,使用命名空间前缀:
blade
<livewire:pages::post.create />传递 props
要向 Livewire 组件传递数据,可以在组件标签上使用 prop 属性:
blade
<livewire:post.create title="Initial Title" />对于动态值或变量,在属性前加冒号:
blade
<livewire:post.create :title="$initialTitle" />传递给组件的数据通过 mount() 方法接收:
php
<?php
use Livewire\Component;
new class extends Component
{
public $title;
public function mount($title = null)
{
$this->title = $title;
}
// ...
};你可以将 mount() 方法视为类构造函数。它在组件初始化时运行,但不会在页面会话中的后续请求中运行。你可以在生命周期文档中了解更多关于 mount() 和其他有用的生命周期钩子的信息。
为了减少样板代码,你可以省略 mount() 方法,Livewire 将自动设置任何名称与传递值匹配的属性:
php
<?php
use Livewire\Component;
new class extends Component
{
public $title; // Automatically set from prop
// ...
};这些属性默认不是响应式的
$title 属性不会在初始页面加载后外部 :title="$initialValue" 改变时自动更新。这是使用 Livewire 时一个常见的困惑点,尤其是对于使用过 Vue 或 React 等 JavaScript 框架的开发者,他们假设这些"参数"的行为像这些框架中的"响应式 props"。但别担心,Livewire 允许你选择使你的 props 响应式。
将路由参数作为 props 传递
当将组件用作页面时,可以直接将路由参数传递给组件。路由参数会自动传递给 mount() 方法:
php
Route::livewire('/posts/{id}', 'pages::post.show');php
<?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 的路由模型绑定:
php
Route::livewire('/posts/{post}', 'pages::post.show');php
<?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 最强大的功能之一,允许你在没有传统控制器的情况下构建整个页面。
php
Route::livewire('/posts/create', 'pages::post.create');当用户访问 /posts/create 时,Livewire 将在应用程序的布局文件中渲染 pages::post.create 组件。
页面组件的工作方式就像普通组件一样,但它们作为完整页面渲染,并可以访问:
- 自定义布局
- 页面标题
- 路由参数和模型绑定
- 布局的命名插槽
有关页面组件的完整信息,包括布局、标题和高级路由,请参阅页面文档。
在视图中访问数据
Livewire 提供了多种方法将数据传递给组件的 Blade 视图。每种方法都有不同的性能和安全特性。
组件属性
最简单的方法是使用公共属性,它们会自动在 Blade 模板中可用:
php
<?php
use Livewire\Component;
new class extends Component
{
public $title = 'My Post';
};blade
<div>
<h1>{{ $title }}</h1>
</div>受保护的属性必须使用 $this-> 访问:
php
public $title = 'My Post'; // 可以作为 {{ $title }} 访问
protected $apiKey = 'secret-key'; // 可以作为 {{ $this->apiKey }} 访问受保护的属性不会发送到前端
与公共属性不同,受保护的属性永远不会发送到前端,用户也无法操纵它们。这使它们对敏感数据来说是安全的。然而,它们不会在请求之间持久化,这限制了它们在大多数 Livewire 场景中的用处。它们最适合用于在属性声明中定义的静态值,你不希望它们暴露给前端。
有关属性的完整信息,包括持久化行为和高级功能,请参阅属性文档。
计算属性
计算属性是像缓存属性一样的方法。它们非常适合昂贵的操作,如数据库查询:
php
use Livewire\Attributes\Computed;
#[Computed]
public function posts()
{
return Post::with('author')->latest()->get();
}blade
<div>
@foreach ($this->posts as $post)
<article>{{ $post->title }}</article>
@endforeach
</div>注意 $this-> 前缀 - 这告诉 Livewire 调用方法并缓存结果。有关更多详细信息,请参阅属性文档中的计算属性章节。
从 render() 传递数据
与控制器类似,你可以使用 render() 方法直接将数据传递给视图:
php
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 文件中定义额外的命名空间:
php
'component_namespaces' => [
'layouts' => resource_path('views/layouts'),
'pages' => resource_path('views/pages'),
'admin' => resource_path('views/admin'), // 自定义命名空间
'widgets' => resource_path('views/widgets'), // 另一个自定义命名空间
],然后在创建、渲染和路由时使用它们:
shell
php artisan make:livewire admin::users-tableblade
<livewire:admin::users-table />php
Route::livewire('/admin/users', 'admin::users-table');额外的组件位置
如果你希望 Livewire 在默认目录之外的其他目录中发现组件,可以在 config/livewire.php 文件中配置它们:
php
'component_paths' => [
resource_path('views/components'),
resource_path('views/admin/components'),
resource_path('views/widgets'),
],现在 Livewire 将自动在所有这些目录中发现组件。
程序化注册
对于更动态的场景(如包开发或运行时配置),你可以在服务提供者中以程序方式注册组件、位置和命名空间:
注册单个组件:
php
use Livewire\Livewire;
// 在服务提供者的 boot() 方法中(例如 App\Providers\AppServiceProvider)
Livewire::addComponent(
name: 'custom-button',
path: resource_path('views/ui/button.blade.php')
);注册组件目录:
php
Livewire::addLocation(
path: resource_path('views/admin/components')
);注册命名空间:
php
Livewire::addNamespace(
namespace: 'ui',
path: resource_path('views/ui')
);当你需要有条件地注册组件或构建提供 Livewire 组件的 Laravel 包时,这种方法很有用。
基于类的组件
对于从 Livewire v3 迁移的团队或那些更喜欢传统 Laravel 结构的人,Livewire 完全支持基于类的组件。这种方法将 PHP 类和 Blade 视图分离到它们传统的 Laravel 位置的不同文件中。
创建基于类的组件
shell
php artisan make:livewire CreatePost --class这会创建两个单独的文件:
app/Livewire/CreatePost.php
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
blade
<div>
{{-- ... --}}
</div>何时使用基于类的组件
在以下情况下使用基于类的组件:
- 从 Livewire v2/v3 迁移
- 你的团队更喜欢传统的 Laravel 文件结构
- 你已经建立了围绕基于类的架构的惯例
- 在重视一致分离模式的大型团队中工作
在以下情况下使用单文件或多文件组件:
- 启动新的 Livewire v4 项目
- 你想要更好的组件归置
- 你的团队更喜欢现代的基于组件的模式
- 你想要单文件简单性的好处,并可以选择以后拆分
配置默认组件类型
如果你希望默认使用基于类的组件,在 config/livewire.php 中配置它:
php
'make_command' => [
'type' => 'class',
],注册基于类的组件
基于类的组件可以使用之前显示的相同方法手动注册,但使用 class 参数而不是 path:
php
use Livewire\Livewire;
use App\Livewire\CustomButton;
// 在服务提供者的 boot() 方法中(例如 App\Providers\AppServiceProvider)
// 注册单个基于类的组件
Livewire::addComponent(
name: 'custom-button',
class: CustomButton::class
);
// 注册基于类的组件的位置
Livewire::addLocation(
class: 'App\\Admin\\Livewire'
);
// 为基于类的组件创建命名空间
Livewire::addNamespace(
namespace: 'admin',
class: 'App\\Admin\\Livewire'
);自定义组件存根
你可以通过运行以下命令自定义 Livewire 用于生成新组件的文件(或_存根_):
shell
php artisan livewire:stubs这会在你的应用程序中创建可以修改的存根文件:
单文件组件存根:
stubs/livewire-sfc.stub— 单文件组件
多文件组件存根:
stubs/livewire-mfc-class.stub— 多文件组件的 PHP 类stubs/livewire-mfc-view.stub— 多文件组件的 Blade 视图stubs/livewire-mfc-js.stub— 多文件组件的 JavaScriptstubs/livewire-mfc-test.stub— 多文件组件的 Pest 测试
基于类的组件存根:
stubs/livewire.stub— 基于类的组件的 PHP 类stubs/livewire.view.stub— 基于类的组件的 Blade 视图
额外的存根:
stubs/livewire.attribute.stub— 属性类stubs/livewire.form.stub— 表单类stubs/livewire.test.stub— PHPUnit 测试文件stubs/livewire.pest-test.stub— Pest 测试文件
一旦发布,Livewire 将在生成新组件时自动使用你的自定义存根。
故障排除
找不到组件
症状: 类似 "Component [post.create] not found" 或 "Unable to find component" 的错误消息
解决方案:
- 验证组件文件存在于预期路径
- 检查视图中的组件名称是否与文件结构匹配(子目录使用点)
- 对于命名空间组件,确保命名空间在
config/livewire.php中定义 - 尝试清除视图缓存:
php artisan view:clear - 如果使用基于类的组件,确保 PHP 文件中的命名空间正确
组件显示空白或不渲染
常见原因:
- Blade 模板中缺少根元素(Livewire 需要恰好一个根元素)
- 组件的 PHP 部分存在语法错误
- 检查 Laravel 日志以获取详细的错误消息
命名空间不工作
症状: 找不到像 pages::post.create 这样的命名空间组件
解决方案:
- 确保命名空间在
config/livewire.php的component_namespaces下定义 - 检查路径映射是否正确:
'pages' => resource_path('views/pages') - 验证组件文件存在于正确的目录中
- 清除配置缓存:
php artisan config:clear
类名冲突
症状: 使用单文件组件时出现关于重复类名的错误
解决方案: 如果你在不同目录中有多个同名的单文件组件,就会发生这种情况。可以:
- 将其中一个组件重命名为唯一的
- 转换为基于类的组件,你可以完全控制命名空间
下一步
现在你已经了解了 Livewire 组件,以下是接下来要探索的关键概念: