跳到内容

StimulusBundle:Symfony 与 Stimulus 的集成

编辑此页

提示

http://ux.symfony.ac.cn 查看 Symfony UX 的实时演示!

此扩展包添加了 Symfony、Stimulus 和 Symfony UX 包之间的集成

  • Twig stimulus_ 函数和过滤器,用于在模板中添加 Stimulus 控制器、
    操作和目标;
  • 集成加载 UX 包(额外的 Stimulus 控制器)

安装

首先,如果您还没有资源处理系统,请选择并安装一个;两者都与 StimulusBundle 配合良好

请参阅 Encore 与 AssetMapper,了解哪一个最适合您的项目。

接下来,安装扩展包

1
$ composer require symfony/stimulus-bundle

如果您正在使用 Symfony Flex,那就完成了!配方将更新必要的文件。如果不是,或者您感到好奇,请参阅手动设置

提示

如果您正在使用 Encore,请务必安装您的资源(例如 npm install)并重启 Encore。

用法

现在您可以在 assets/controllers 目录中创建自定义 Stimulus 控制器。实际上,您应该已经有一个示例控制器在那里了:hello_controller.js

1
2
3
4
5
6
7
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
    connect() {
        this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
    }
}

然后,在您的 HTML 中激活控制器

1
2
3
<div data-controller="hello">
   ...
</div>

可选地,此扩展包有一个 Twig 函数来渲染属性

1
2
3
4
5
6
7
8
<div {{ stimulus_controller('hello') }}>
    ...
</div>

<!-- would render -->
<div data-controller="hello">
   ...
</div>

就是这样!每当此元素出现在页面上时,hello 控制器将被激活。

关于 Stimulus 还有很多要学习的。请参阅 Stimulus 文档了解所有详细信息。

TypeScript 控制器

如果您想使用 TypeScript 定义您的控制器,您可以这样做!安装并设置 sensiolabs/typescript-bundle。然后确保将 assets/controllers 路径添加到 sensiolabs_typescript.source_dir 配置中。最后,在该目录中创建您的控制器,您就可以开始了。

UX 包

Symfony 提供了一组 UX 包,这些包添加了额外的 Stimulus 控制器来解决常见问题。StimulusBundle 会激活您的 assets/controllers.json 文件中提到的任何第三方 Stimulus 控制器。每当您安装 UX 包时,此文件都会更新。

官方 UX 包有:

延迟加载 Stimulus 控制器

默认情况下,您的所有控制器(即 assets/controllers/ 中的文件 + assets/controllers.json 中的控制器)将在每个页面上下载和加载。

有时您可能有一个控制器仅在某些页面上使用。在这种情况下,您可以将控制器设置为“延迟加载”。在这种情况下,它不会在初始页面加载时下载。相反,一旦页面上出现与控制器匹配的元素(例如 <div data-controller="hello">),控制器及其导入的任何其他内容将通过 Ajax 延迟加载。

要使您的自定义控制器之一延迟加载,请在顶部添加一个特殊注释

1
2
3
4
5
6
import { Controller } from '@hotwired/stimulus';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
    // ...
}

要使第三方控制器延迟加载,请在 assets/controllers.json 中将 fetch 设置为 lazy

注意

如果您使用 TypeScript 编写控制器并且您正在使用 StimulusBundle ≤ 2.21.0,请确保在您的 TypeScript 配置中 removeComments 未设置为 true

世界各地的 Stimulus 工具

因为 Stimulus 被 Symfony 以外的开发人员使用,所以除了 UX 包之外还存在许多工具

  • stimulus-use:为您的 Stimulus 控制器添加可组合的行为,例如防抖动、检测外部点击以及许多其他功能。
  • stimulus-components:大量预制的 Stimulus 控制器,例如用于复制到剪贴板、排序、弹出框(类似于工具提示)等等。

Stimulus Twig 助手

此扩展包添加了一些 Twig 函数/过滤器,以帮助在您的模板中添加 Stimulus 控制器、操作和目标。

注意

尽管此扩展包提供了这些有用的 Twig 函数/过滤器,但建议使用原始数据属性,因为它们更直接。

提示

如果您使用 PhpStorm IDE - 您可能需要安装 Stimulus 插件以获得属性的良好自动完成功能。

stimulus_controller

此扩展包附带一个特殊的 stimulus_controller() Twig 函数,可用于渲染 Stimulus 控制器和值以及 CSS 类。Stimulus 控制器还可以通过使用 Outlets 引用其他控制器。

例如

1
2
3
4
5
6
7
8
9
10
11
12
<div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }) }}>
    Hello
</div>

<!-- would render -->
<div
   data-controller="chart"
   data-chart-name-value="Likes"
   data-chart-data-value="&#x5B;1,2,3,4&#x5D;"
>
   Hello
</div>

如果您想设置 CSS 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }, { 'loading': 'spinner' }) }}>
    Hello
</div>

<!-- would render -->
<div
   data-controller="chart"
   data-chart-name-value="Likes"
   data-chart-data-value="&#x5B;1,2,3,4&#x5D;"
   data-chart-loading-class="spinner"
>
   Hello
</div>

<!-- or without values -->
<div {{ stimulus_controller('chart', controllerClasses = { 'loading': 'spinner' }) }}>
    Hello
</div>

以及使用 outlets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }, { 'loading': 'spinner' }, { 'other': '.target' ) }}>
    Hello
</div>

<!-- would render -->
<div
   data-controller="chart"
   data-chart-name-value="Likes"
   data-chart-data-value="&#x5B;1,2,3,4&#x5D;"
   data-chart-loading-class="spinner"
   data-chart-other-outlet=".target"
>
   Hello
</div>

<!-- or without values/classes -->
<div {{ stimulus_controller('chart', controllerOutlets = { 'other': '.target' }) }}>
    Hello
</div>

任何非标量值(例如 data: [1, 2, 3, 4])都经过 JSON 编码。并且所有值都已正确转义(字符串 &#x5B; 是转义的 [ 字符,因此属性实际上是 [1,2,3,4])。

如果您在同一个元素上有多个控制器,您可以将它们链接起来,因为还有一个 stimulus_controller 过滤器

1
2
3
4
5
6
7
8
<div {{ stimulus_controller('chart', { 'name': 'Likes' })|stimulus_controller('other-controller') }}>
    Hello
</div>

<!-- would render -->
<div data-controller="chart other-controller" data-chart-name-value="Likes">
    Hello
</div>

您还可以将生成的属性作为数组检索,这对于表单等情况可能很有用

1
{{ form_start(form, { attr: stimulus_controller('chart', { 'name': 'Likes' }).toArray() }) }}

stimulus_action

stimulus_action() Twig 函数可用于渲染 Stimulus 操作

例如

1
2
3
4
5
6
<div {{ stimulus_action('controller', 'method') }}>Hello</div>
<div {{ stimulus_action('controller', 'method', 'click') }}>Hello</div>

<!-- would render -->
<div data-action="controller#method">Hello</div>
<div data-action="click->controller#method">Hello</div>

如果您在同一个元素上有多个操作和/或方法,您可以将它们链接起来,因为还有一个 stimulus_action 过滤器

1
2
3
4
5
6
7
8
<div {{ stimulus_action('controller', 'method')|stimulus_action('other-controller', 'test') }}>
    Hello
</div>

<!-- would render -->
<div data-action="controller#method other-controller#test">
    Hello
</div>

您还可以将生成的属性作为数组检索,这对于表单等情况可能很有用

1
{{ form_row(form.password, { attr: stimulus_action('hello-controller', 'checkPasswordStrength').toArray() }) }}

您还可以将参数传递给操作

1
2
3
4
<div {{ stimulus_action('hello-controller', 'method', 'click', { 'count': 3 }) }}>Hello</div>

<!-- would render -->
<div data-action="click->hello-controller#method" data-hello-controller-count-param="3">Hello</div>

stimulus_target

stimulus_target() Twig 函数可用于渲染 Stimulus 目标

例如

1
2
3
4
5
6
<div {{ stimulus_target('controller', 'myTarget') }}>Hello</div>
<div {{ stimulus_target('controller', 'myTarget secondTarget') }}>Hello</div>

<!-- would render -->
<div data-controller-target="myTarget">Hello</div>
<div data-controller-target="myTarget secondTarget">Hello</div>

如果您在同一个元素上有多个目标,您可以将它们链接起来,因为还有一个 stimulus_target 过滤器

1
2
3
4
5
6
7
8
<div {{ stimulus_target('controller', 'myTarget')|stimulus_target('other-controller', 'anotherTarget') }}>
    Hello
</div>

<!-- would render -->
<div data-controller-target="myTarget" data-other-controller-target="anotherTarget">
    Hello
</div>

您还可以将生成的属性作为数组检索,这对于表单等情况可能很有用

1
{{ form_row(form.password, { attr: stimulus_target('hello-controller', 'myTarget').toArray() }) }}

配置

如果您正在使用 AssetMapper,如果您需要使用不同的路径,则可以配置控制器目录和 controllers.json 文件的路径

1
2
3
4
5
6
# config/packages/stimulus.yaml
stimulus:
    # the default values
    controller_paths:
        - '%kernel.project_dir%/assets/controllers'
    controllers_json: '%kernel.project_dir%/assets/controllers.json'

手动安装详情

当您安装此扩展包时,其 Flex 配方应处理更新所有需要的文件。如果您未使用 Flex 或想仔细检查更改,请查看 StimulusBundle Flex 配方。以下是其中内容的摘要

  • assets/bootstrap.js 启动 Stimulus 应用程序并加载您的控制器。它由 assets/app.js 导入,其确切内容取决于您是否安装了 Webpack Encore 或 AssetMapper(见下文)。
  • assets/app.js 已更新为导入 assets/bootstrap.js
  • assets/controllers.json 此文件开始时(大部分)为空,并在您安装提供 Stimulus 控制器的 UX 包时自动更新。
  • assets/controllers/ 此目录是您应该放置自定义 Stimulus 控制器的地方。它带有一个示例 hello_controller.js 文件。

其他一些更改取决于您使用的资源系统

使用 AssetMapper

如果您正在使用 AssetMapper,则会在您的 importmap.php 文件中添加两个新条目

1
2
3
4
5
6
7
8
9
10
11
// importmap.php
return [
    // ...

    '@symfony/stimulus-bundle' => [
        'path' => '@symfony/stimulus-bundle/loader.js',
    ],
    '@hotwired/stimulus' => [
        'version' => '3.2.2',
    ],
];

配方将更新您的 assets/bootstrap.js 文件,使其看起来像这样

1
2
3
4
// assets/bootstrap.js
import { startStimulusApp } from '@symfony/stimulus-bundle';

const app = startStimulusApp();

@symfony/stimulus-bundle 指的是您的 importmap.php 文件中的新条目之一。此文件由扩展包动态构建,并将导入您的所有自定义控制器以及来自 controllers.json 的控制器。当您的应用程序在调试模式下运行时,它还将在 Stimulus 中动态启用“调试”模式。

提示

仅对于 AssetMapper 6.3,您还需要在 base.html.twig 中使用 {{ ux_controller_link_tags() }}。AssetMapper 6.4+ 中不需要此项。

使用 WebpackEncoreBundle

如果您正在使用 Webpack Encore,则配方还将更新您的 webpack.config.js 文件以包含此行

1
2
// webpack.config.js
.enableStimulusBridge('./assets/controllers.json')

assets/bootstrap.js 文件将更新为如下所示

1
2
3
4
5
6
7
8
9
// assets/bootstrap.js
import { startStimulusApp } from '@symfony/stimulus-bridge';

// Registers Stimulus controllers from controllers.json and in the controllers/ directory
export const app = startStimulusApp(require.context(
    '@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
    true,
    /\.[jt]sx?$/
));

并且 2 个新软件包 - @hotwired/stimulus@symfony/stimulus-bridge - 将添加到您的 package.json 文件中。

Stimulus 控制器是如何加载的?

当您安装 UX PHP 包时,Symfony Flex 会自动更新您的 package.json 文件(如果使用 AssetMapper,则不需要这样做)以指向位于该 PHP 包内的“虚拟包”。例如

1
2
3
4
5
6
{
    "devDependencies": {
        "...": "",
        "@symfony/ux-chartjs": "file:vendor/symfony/ux-chartjs/assets"
    }
}

这为您提供了一个真正的 Node 包(例如 @symfony/ux-chartjs),它不是被下载,而是直接指向已存在于您的 vendor/ 目录中的文件。

Flex 配方通常还会更新您的 assets/controllers.json 文件,以向您的应用程序添加新的 Stimulus 控制器。例如

1
2
3
4
5
6
7
8
9
10
11
{
    "controllers": {
        "@symfony/ux-chartjs": {
            "chart": {
                "enabled": true,
                "fetch": "eager"
            }
        }
    },
    "entrypoints": []
}

最后,您的 assets/bootstrap.js 文件将自动注册

  • assets/controllers/ 中的所有文件作为 Stimulus 控制器;
  • 以及 assets/controllers.json 中描述的所有控制器作为 Stimulus 控制器。

注意

如果您正在使用 WebpackEncore,则 bootstrap.js 文件与 @symfony/stimulus-bridge 协同工作。对于 AssetMapper,bootstrap.js 文件直接与此扩展包一起工作:通过 Flex 将 @symfony/stimulus-bundle 条目添加到您的 importmap.php 文件中,该条目指向一个动态构建的文件,用于查找和加载您的控制器(请参阅配置)。

最终结果:您安装一个包,并且立即拥有可用的 Stimulus 控制器!在本例中,它被称为 @symfony/ux-chartjs/chart。好吧,从技术上讲,它将被称为 symfony--ux-chartjs--chart。但是,您可以将原始名称传递到 WebpackEncoreBundle 中的 {{ stimulus_controller() }} 函数,它会将其规范化

1
2
3
4
<div {{ stimulus_controller('@symfony/ux-chartjs/chart') }}>

<!-- will render as: -->
<div data-controller="symfony--ux-chartjs--chart">
这项工作,包括代码示例,均根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本