danmartuszewski / ux-twig-component
为 Symfony 提供的 Twig 组件
Requires
- php: >=7.2.5
- symfony/dependency-injection: ^4.4|^5.0
- symfony/property-access: ^4.4|^5.0
- twig/twig: ^2.0|^3.0
Requires (Dev)
- symfony/framework-bundle: ^4.4|^5.0
- symfony/phpunit-bridge: ^5.2
- symfony/twig-bundle: ^4.4|^5.0
Conflicts
- symfony/dependency-injection: <4.4.18,<5.1.10,<5.2.1
This package is auto-updated.
Last update: 2024-09-18 18:01:16 UTC
README
实验性 该组件目前处于实验性阶段,可能会发生变化,甚至发生重大变化。
Twig 组件使您能够将对象绑定到模板,从而更容易渲染和重用小的模板 "单元",例如 "警告",模态的标记,或分类侧边栏
每个组件都由以下内容组成(1)一个类
// src/Components/AlertComponent.php namespace App\Components; use Symfony\UX\TwigComponent\AbstractComponent; class AlertComponent extends AbstractComponent { public string $type = 'success'; public string $message; public static function getComponentName(): string { return 'alert'; } // optional, specify template name public static function getTemplate() : ?string { return '@App/components/alert.html.twig'; } }
和(2)相应的模板
{# templates/components/alert.html.twig #} <div class="alert alert-{{ this.type }}"> {{ this.message }} </div>
完成!现在在您想要的地方渲染它
{{ component('alert', { message: 'Hello Twig Components!' }) }}
享受您的新组件!
这将从客户端框架中引入熟悉的 "组件" 系统,进入 Symfony。结合 Live Components,创建一个具有自动、Ajax 渲染的交互式前端。
安装
让我们开始安装!运行
composer require symfony/ux-twig-component
这就完了!我们准备好了!
创建一个基本组件
让我们创建一个可重用的 "警告" 元素,我们可以在整个网站上使用它来显示成功或错误消息。第一步总是创建一个实现 ComponentInterface
的组件。让我们尽可能简单开始
// src/Components/AlertComponent.php namespace App\Components; use Symfony\UX\TwigComponent\ComponentInterface; class AlertComponent implements ComponentInterface { public static function getComponentName(): string { return 'alert'; } }
第二步是为该组件创建一个模板。模板位于 templates/components/{Component Name}.html.twig
,其中 {Component Name}
是您从 getComponentName()
方法返回的内容
{# templates/components/alert.html.twig #} <div class="alert alert-success"> Success! You've created a Twig component! </div>
目前这并不有趣...因为消息是硬编码到模板中的。但这足够了!通过从任何其他 Twig 模板渲染您的组件来庆祝
{{ component('alert') }}
完成!您刚刚渲染了第一个 Twig 组件!花点时间挥舞拳头 - 然后回来!
将数据传递到您的组件中
这是一个好开始:但这并不有趣!为了使我们的 alert
组件可重用,我们需要使消息和类型(例如 success
、danger
等)可配置。要做到这一点,为每个创建一个公共属性
// src/Components/AlertComponent.php // ... class AlertComponent implements ComponentInterface { + public string $message; + public string $type = 'success'; // ... }
在模板中,AlertComponent
实例可通过 this
变量访问。使用它来渲染这两个新属性
<div class="alert alert-{{ this.type }}"> {{ this.message }} </div>
如何填充 message
和 type
属性?通过在渲染 component()
函数时将其作为第二个参数传递
{{ component('alert', { message: 'Successfully created!' }) }} {{ component('alert', { type: 'danger', message: 'Danger Will Robinson!' }) }}
幕后,将实例化一个新的 AlertComponent
,并将 message
键(以及传递的 type
)设置为对象的 $message
属性。然后,渲染组件!如果属性有一个设置器方法(例如 setMessage()
),则将调用该方法而不是直接设置属性。
mount() 方法
如果您出于某种原因不想将选项直接设置为 component()
函数的属性,则可以在组件中创建一个 mount()
方法
// src/Components/AlertComponent.php // ... class AlertComponent implements ComponentInterface { public string $message; public string $type = 'success'; public function mount(bool $isSuccess = true) { $this->type = $isSuccess ? 'success' : 'danger'; } // ... }
mount()
方法在组件实例化后立即被调用一次。由于方法有一个 $isSuccess
参数,因此可以在渲染组件时传递一个 isSuccess
选项
{{ component('alert', { isSuccess: false, message: 'Danger Will Robinson!' }) }}
如果选项名称与 mount()
中的参数名称匹配,则将选项作为该参数传递,组件系统将 不会 尝试直接将其设置为属性。
获取服务
让我们创建一个更复杂的示例:一个“特色产品”组件。你可以选择将一个产品对象数组传递给component()
函数,并在$products
属性上设置这些。但让我们允许组件执行查询的工作。
如何?组件是服务,这意味着自动装配就像正常一样工作。此示例假设你有一个Product
Doctrine实体和ProductRepository
。
// src/Components/FeaturedProductsComponent.php namespace App\Components; use App\Repository\ProductRepository; use Symfony\UX\TwigComponent\ComponentInterface; class FeaturedProductsComponent implements ComponentInterface { private ProductRepository $productRepository; public function __construct(ProductRepository $productRepository) { $this->productRepository = $productRepository; } public function getProducts(): array { // an example method that returns an array of Products return $this->productRepository->findFeatured(); } public static function getComponentName() : string { return 'featured_products'; } }
在模板中,可以通过this.products
访问getProducts()
方法。
{# templates/components/featured_products.html.twig #} <div> <h3>Featured Products</h3> {% for product in this.products %} ... {% endfor %} </div>
由于此组件没有任何需要填充的公共属性,你可以用以下方式渲染它:
{{ component('featured_products') }}
注意 因为组件是服务,所以可以使用正常的依赖注入。但是,每个组件服务都注册为shared: false
。这意味着你可以安全地多次使用不同的数据渲染相同的组件,因为每个组件都将是一个独立的实例。
计算属性
在上一个示例中,我们没有立即查询特色产品(例如在__construct()
中),而是创建了一个getProducts()
方法,并通过this.products
从模板中调用该方法。
这样做是因为,作为一般规则,你应该尽可能使你的组件延迟执行,并只在其属性上存储你需要的信息(这也帮助你在以后将组件转换为实时组件)。在这个设置中,只有当实际调用getProducts()
方法时,才会执行查询。这与Vue等框架中的“计算属性”概念非常相似。
但是,getProducts()
方法并没有魔法:如果你在模板中多次调用this.products
,查询将会多次执行。
为了使你的getProducts()
方法表现得像真正的计算属性(其值只在第一次调用该方法时计算),你可以在私有属性上存储其结果。
// src/Components/FeaturedProductsComponent.php namespace App\Components; // ... class FeaturedProductsComponent implements ComponentInterface { private ProductRepository $productRepository; + private ?array $products = null; // ... public function getProducts(): array { + if ($this->products === null) { + $this->products = $this->productRepository->findFeatured(); + } - return $this->productRepository->findFeatured(); + return $this->products; } }
贡献
有兴趣贡献吗?请访问此存储库的主源:https://github.com/symfony/ux/tree/main/src/TwigComponent。
祝你好运!