
简介
在 Symfony UX 中,有两个包:TwigComponents 和 LiveComponent。 这些包允许您在 Symfony 应用程序中创建可重用的组件。 然而,组件架构并非 Symfony 独有;它是一种可以应用于任何编程语言或框架的设计模式。 JavaScript 世界长期以来一直在许多框架(如 React、Vue 或 Svelte)中实施这种架构。 一组用于组件工作的规则和模式已经被定义。 这就是 Symfony UX 尝试紧密遵循这些规则的原因。 让我们探索一下这些规则是什么!
4 个规则
组合
页面不再仅仅是一个页面,而是一个由小的、可重用组件组成的集合。 这些组件可以组装成一个页面。 例如,可以有一个用于标题的组件,另一个用于培训列表的组件。 培训列表组件甚至可以由更小的组件组成,例如培训卡组件。 目标是创建尽可能原子化和可重用的组件。
在 Symfony 中如何工作?
在 Symfony 中,例如,您可以拥有一个 Alert
组件,其模板如下
<div class="alert alert-{{ type }}"> <twig:ux:icon name="{{ icon }}" /> {{ message }} </div>
在这里您可以看到我们有一个 Alert
组件,它本身使用了 Icon
组件。或者您可以使用以下语法进行组合
<twig:Card> <twig:ux:icon name="info"/> <twig:Button> <twig:ux:icon name="close" /> </twig:Button> </twig:Card>
在这里我们有一个 Card
组件,我们使用另外两个组件来提供此组件的内容。
独立性
这是一个非常重要的规则,但并不明显。 您的组件应该存在于自己的上下文中;它不应该意识到页面的其余部分。 您应该能够将一个组件从一个页面移动到另一个页面,并且它应该完全相同地工作。 此规则使您的组件真正可重用。
在 Symfony 中如何工作?
Symfony 将页面的上下文保留在组件的上下文中。 因此,您有责任遵守这些规则。 请注意,如果上下文页面中的变量与您的组件之间存在冲突,则您的组件上下文会覆盖页面上下文。
Props (属性)
我们的组件必须保持独立性,但我们可以自定义其 props。 例如,考虑一个按钮组件。 您希望您的组件在每个页面上看起来都相同,唯一的变化是标签。 为此,您可以在按钮组件中声明一个 label
prop。 当您使用按钮组件时,您可以传递您想要的标签作为 prop。 组件将在初始化时获取此 prop,并在其整个生命周期中保留它。
在 Symfony 中如何工作?
让我们以 Alert
组件作为匿名组件为例。 我们有以下模板
{% props type, icon, message %} <div class="alert alert-{{ type }}"> <twig:ux:icon name="{{ icon }}" /> {{ message }} </div>
就像这样,我们为 Alert
组件定义了三个 props。我们现在可以像这样使用它
<twig:Alert type="success" icon="check" message="Your account has been created." />
如果您的组件不是匿名组件而是类组件,您可以通过向您的类添加属性来定义 props。
#[AsTwigComponent] class Alert { public string $type; public string $icon; public string $message; }
关于 props 有一点很重要需要注意:它们应该只沿一个方向流动,从父组件到子组件。 Props 永远不应该向上流动。 如果您的子组件需要更改父组件中的某些内容,则应使用事件。
State (状态)
State 很像 prop,但主要区别在于 state 可以在组件的生命周期内更改。 让我们以按钮组件为例。 您可以拥有一个 loading
state,它可以是 true
或 false
。 当按钮被点击时,loading
state 可以设置为 true
,按钮可以显示加载器而不是标签。 加载完成后,可以将 loading
state 设置为 false
,按钮可以再次显示标签。
在 Symfony 中如何工作?
在 Symfony 中,您有两种不同的方法来处理 state。 第一种是直接在您的组件中使用 Stimulus。 我们建议在组件的根目录设置一个 Stimulus 控制器。
{% props label %} <button data-controller="button" data-button-label-value="{{ label }}"> {{ label }} </button>
然后,您可以像这样定义您的控制器
import { Controller } from '@hotwired/stimulus'; export default class extends Controller { static values = { label: String }; connect() { this.element.textContent = this.labelValue; } loading() { this.element.textContent = 'Loading...'; } }
第二种方法是使用 LiveComponent 包。 如何在这两者之间做出选择? 如果您的组件的状态不需要任何后端逻辑,请保持简单并使用 Stimulus 方法。 但是,如果您的状态需要处理后端逻辑,请使用 LiveComponent。 使用 LiveComponent,live prop 就是 state。 因此,如果您想存储按钮上的点击次数,可以使用以下组件来实现
<?php #[AsLiveComponent] class Button { use DefaultActionTrait; #[LiveProp] public int $clicks = 0; #[LiveAction] public function increment(): void { $this->clicks++; $this->save(); } }
结论
即使在 Symfony 中,您也可以使用组件架构。 遵循这些规则有助于您的前端开发人员处理他们熟悉的代码库,因为这些规则已经在 JavaScript 世界中得到广泛使用。