Blade class 组件需定义继承 Illuminate\View\Component 的 PHP 类并实现 render() 方法,类须置于 app/View/Components/ 下且通过 artisan 命令生成;匿名组件则为 resources/views/components/ 下的纯 Blade 文件,通过 @props 声明属性,无需 PHP 类。

Blade class 组件:必须定义完整 PHP 类
Blade class 组件不是直接写在视图里就能用的,它要求你先创建一个继承 Illuminate\View\Component 的 PHP 类,并在其中定义 render() 方法。Laravel 不会自动扫描视图目录下的 PHP 文件——类必须放在 app/View/Components/ 下,且需通过 php artisan make:component Alert 命令生成(否则命名空间、目录结构或自动发现容易出错)。
常见错误是把 class 组件当成普通模板直接 @include,结果报错 Class "App\View\Components\Alert" not found。正确做法是:运行命令生成类 → 在 render() 中返回 view('components.alert') → 然后在 Blade 中用 调用。
参数传递靠构造函数和 public 属性,例如:
class Alert extends Component
{
public string $type;
public string $message;
public function __construct(string $type = 'info', string $message = '')
{
$this->type = $type;
$this->message = $message;
}
public function render()
{
return view('components.alert');
}}
注意:构造函数参数不能是可选类型(如 ?string),否则 Laravel 无法解析依赖;$message 默认空字符串是安全的,但 null 会导致绑定失败。
Blade 匿名组件:零 PHP 类,直接复用视图文件
匿名组件本质就是一个带 @props 声明的 Blade 文件,无需 PHP 类、无需注册、不走服务容器。它适合轻量、无逻辑、纯展示型复用,比如按钮、卡片外壳、表单字段包装器。
使用前提是:文件必须放在 resources/views/components/ 目录下(如 resources/views/components/card.blade.php),且文件名决定标签名(card.blade.php → )。路径层级不影响调用,但不能嵌套子目录(components/ui/card.blade.php 不会被识别)。
@props 必须写在文件顶部,且只能出现一次;它接收传入的属性并自动转为变量:
@props(['title' => '', 'border' => true])
merge(['class' => 'p-4 rounded']) }}>
@if($title){{ $title }}
@endif
{{ $slot }}
调用时:内容区 。注意:$attributes 是默认注入的,用于透传未声明的 HTML 属性(如 id、data-* );$slot 是组件标签内的内容。
class vs 匿名组件:关键差异在哪
二者根本区别不在语法,而在执行时机和能力边界:
- class 组件在渲染前经过 PHP 实例化,支持依赖注入(如
Request、Auth)、数据库查询、复杂条件判断;匿名组件只做变量替换,无法调用服务或执行业务逻辑 - class 组件的属性校验靠 PHP 类型提示 + 构造函数,报错明确;匿名组件的
@props没有类型检查,传错参数(如传数组给期望字符串的$title)可能只在运行时报 Notice 或渲染异常 - class 组件可通过
public $foo暴露属性供模板访问,也可定义方法(如public function cssClasses());匿名组件只能靠@props和内联逻辑 - 性能上,匿名组件略快(少一次类加载与实例化),但差异微乎其微;可维护性上,逻辑复杂时 class 组件更易测试和复用
容易被忽略的 slot 与 attributes 处理细节
无论是 class 还是匿名组件,$slot 和 $attributes 都不是“自动可用”的魔法变量——它们必须显式出现在模板中,且位置决定最终 HTML 结构。漏写 {{ $slot }} 就等于丢掉所有子内容;漏写 {{ $attributes }} 就等于丢掉外部传入的 class、id 等属性。
常见陷阱:
-
$attributes->merge([...])会覆盖同名属性(如外部传了class="btn",而merge(['class' => 'btn-primary'])会完全替换,不是追加);要用class="{{ $attributes->get('class', '') }} btn-primary"手动拼接 -
$slot是Illuminate\Support\HtmlString实例,不能直接用isset($slot)判断是否有内容,得用!$slot->isEmpty()或strlen($slot) > 0 - 多 slot 场景(如
)只在 class 组件中稳定支持;匿名组件不支持具名 slot,强行用会静默失效...










