跳到内容

设计

编辑此页

后端的设计已为任何类型的应用程序做好准备。它使用 Bootstrap 5 以及一些自定义 CSS 和 JavaScript 代码创建;所有这些都由 Webpack 通过 Symfony 的 Webpack Encore 进行管理。

与任何其他 Symfony 扩展包一样,资源在安装或更新扩展包时被复制到(或符号链接自)应用程序的 public/bundles/ 目录。如果由于任何原因这不起作用,您的后端将不会显示正确的 CSS/JS 样式。在这些情况下,运行此命令以手动安装这些资源

1
2
# remove the --symlink option if your system doesn't support symbolic links
$ php bin/console assets:install --symlink

根据您的需求,有几种自定义设计的方法。其中一些需要纯 CSS/JavaScript 代码,另一些则需要覆盖和/或创建新的 Twig 模板。

更改后端图标

4.16

配置图标集的选项在 EasyAdmin 4.16.0 中引入。

默认情况下,EasyAdmin 对内置界面图标以及您添加到菜单项、字段、表单选项卡等的任何自定义图标都使用 FontAwesome 图标。完整的 FontAwesome 图标集(约 2,000 个图标)已包含在 EasyAdmin 中,因此您无需下载任何这些图标。

如果您希望使用其他图标,请在您的仪表盘中调用 useCustomIconSet()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\IconSet;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    public function configureAssets(): Assets
    {
        return Assets::new()
            ->useCustomIconSet()
        ;
    }

    // ...
}

然后,每当您为任何 EasyAdmin 功能定义自定义图标时,请使用完整的图标前缀和名称(lucide:map-pinic:baseline-calendar-month 等),这通常在 Symfony UX Icons 中使用。

如果您的所有图标都使用一个共同的前缀(例如,使用 Tabler 图标时为 tabler:),请将其传递给 useCustomIconSet() 方法

1
return Assets::new()->useCustomIconSet('tabler');

现在,tabler: 前缀将自动添加到您的所有自定义图标名称中。这样,您可以使用诸如 userfile 之类的名称,而不是 tabler:usertabler:file

修改后端模板

后端页面由多个 Twig 模板和片段创建。您可以通过两种方式修改它们

  • 覆盖 EasyAdmin 模板 使用 Symfony 的机制来覆盖模板(这对于所有扩展包都是相同的,不仅仅是 EasyAdmin);
  • 替换 EasyAdmin 模板 使用 EasyAdmin 功能。

覆盖模板

提示

与其使用 Symfony 机制来覆盖模板,您不妨考虑使用 EasyAdmin 提供的类似但更强大的功能来替换模板,如下一节中所述。

按照 Symfony 的 覆盖扩展包模板 机制,您必须在您的应用程序中创建 templates/bundles/EasyAdminBundle/ 目录,然后创建与原始模板路径相同的新模板。例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
your-project/
├─ ...
└─ templates/
   └─ bundles/
      └─ EasyAdminBundle/
         ├─ layout.html.twig
         ├─ menu.html.twig
         ├─ crud/
         │  ├─ index.html.twig
         │  ├─ detail.html.twig
         │  └─ field/
         │     ├─ country.html.twig
         │     └─ text.html.twig
         ├─ label/
         │  └─ null.html.twig
         └─ page/
            ├─ content.html.twig
            └─ login.html.twig

您可以扩展原始模板,而不是从头开始创建新模板,并且仅更改您想要覆盖的部分。但是,您必须在 extends 内使用特殊语法以避免无限循环

1
2
3
4
5
6
7
8
9
10
11
{# templates/bundles/EasyAdminBundle/layout.html.twig #}

{# DON'T DO THIS: it will cause an infinite loop #}
{% extends '@EasyAdmin/layout.html.twig' %}

{# DO THIS: the '!' symbol tells Symfony to extend from the original template #}
{% extends '@!EasyAdmin/layout.html.twig' %}

{% block sidebar %}
    {# ... #}
{% endblock %}

替换模板

此选项允许您使用您自己的 Twig 模板渲染后端的某些部分。首先,您可以在 仪表盘 中全局替换某些模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureCrud(): Crud
    {
        return Crud::new()
            // ...

            // the first argument is the "template name", which is the same as the
            // Twig path but without the `@EasyAdmin/` prefix
            ->overrideTemplate('label/null', 'admin/labels/my_null_label.html.twig')

            ->overrideTemplates([
                'crud/index' => 'admin/pages/index.html.twig',
                'crud/field/textarea' => 'admin/fields/dynamic_textarea.html.twig',
            ])
        ;
    }
}

您还可以按 CRUD 控制器 替换模板(这将覆盖在仪表盘中所做的任何更改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;

class ProductCrudController extends AbstractCrudController
{
    // ...

    public function configureCrud(Crud $crud): Crud
    {
        return $crud
            // ...

            ->overrideTemplate('crud/layout', 'admin/advanced_layout.html.twig')

            ->overrideTemplates([
                'crud/field/text' => 'admin/product/field_id.html.twig',
                'label/null' => 'admin/labels/null_product.html.twig',
            ])
        ;
    }
}

字段和操作模板

每个 字段(和每个 操作)都定义了一个 setTemplatePath() 方法来设置用于渲染该特定字段(或操作)的 Twig 模板

1
2
3
4
5
6
7
8
9
TextField::new('...', '...')
    // ...
    ->setTemplatePath('custom_fields/text.html.twig');

// ...

Action::new('...', '...')
    // ...
    ->setTemplatePath('admin/actions/my_custom_action.html.twig');

setTemplatePath() 方法仅适用于在 indexdetail 页面上显示的字段。阅读下一节以了解如何自定义 newedit 页面中的字段,这些页面使用 Symfony 表单。

表单字段模板

EasyAdmin 提供了一个基于 Bootstrap 5 的即用型 表单主题。仪表盘和 CRUD 控制器定义了 addFormTheme(string $themePath)setFormThemes(array $themePaths) 方法,因此您可以使用您自己的表单主题 自定义单个表单字段

假设有一个表单字段,您想在其中包含一个链接到其他信息的 <a> 元素。如果该字段名为 title 并且属于 Product 实体,则配置如下所示

1
2
3
4
5
TextField::new('title')
    // ...
    ->setFormTypeOptions([
        'block_name' => 'custom_title',
    ]);

下一步是定义该字段使用的模板片段,这需要了解 Symfony 定义的 表单片段命名规则

1
2
3
4
5
6
7
8
{# templates/admin/form.html.twig #}
{# note that the Twig block name starts with an uppercase letter
   ('_Product_...' instead of '_product_...') because the first part
   of the block name is the unmodified entity name #}
{% block _Product_custom_title_widget %}
    {# ... #}
    <a href="...">More information</a>
{% endblock %}

最后,将此自定义主题添加到用于渲染后端表单的主题列表中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;

class ProductCrudController extends AbstractCrudController
{
    // ...

    public function configureCrud(Crud $crud): Crud
    {
        return $crud
            // ...

            // don't forget to add EasyAdmin's form theme at the end of the list
            // (otherwise you'll lose all the styles for the rest of form fields)
            ->setFormThemes(['admin/form.html.twig', '@EasyAdmin/crud/form_theme.html.twig'])
        ;
    }
}

注意

您还可以使用原始字段名称来覆盖表单小部件。在上面的示例中,它看起来像这样:{% block _Product_title_widget %}。完整语法为:{% block _<Entity name>_<Field name>_widget %}

添加自定义 Web 资源

仪表盘 和/或 CRUD 控制器 中使用 configureAssets() 方法添加您自己的 CSS 和 JavaScript 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
namespace App\Controller\Admin;

use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;

class ProductCrudController extends AbstractCrudController
{
    // ...

    public function configureAssets(Assets $assets): Assets
    {
        return $assets
            // imports the given entrypoint defined in the importmap.php file of AssetMapper
            // it's equivalent to adding this inside the <head> element:
            // {{ importmap('admin') }}
            ->addAssetMapperEntry('admin')
            // you can also import multiple entries
            // it's equivalent to calling {{ importmap(['app', 'admin']) }}
            ->addAssetMapperEntry('app', 'admin')

            // adds the CSS and JS assets associated to the given Webpack Encore entry
            // it's equivalent to adding these inside the <head> element:
            // {{ encore_entry_link_tags('...') }} and {{ encore_entry_script_tags('...') }}
            ->addWebpackEncoreEntry('admin-app')

            // it's equivalent to adding this inside the <head> element:
            // <link rel="stylesheet" href="{{ asset('...') }}">
            ->addCssFile('build/admin.css')
            ->addCssFile('https://example.org/css/admin2.css')

            // it's equivalent to adding this inside the <head> element:
            // <script src="{{ asset('...') }}"></script>
            ->addJsFile('build/admin.js')
            ->addJsFile('https://example.org/js/admin2.js')

            // use these generic methods to add any code before </head> or </body>
            // the contents are included "as is" in the rendered page (without escaping them)
            ->addHtmlContentToHead('<link rel="dns-prefetch" href="https://assets.example.com">')
            ->addHtmlContentToBody('<script> ... </script>')
            ->addHtmlContentToBody('<!-- generated at '.time().' -->')
        ;
    }
}

如果您需要自定义 <link><script> 标签的 HTML 属性或其他功能,请将 Asset 对象传递给 addCssFile()addJsFile()addWebpackEncoreEntry() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use EasyCorp\Bundle\EasyAdminBundle\Config\Asset;
// ...

return $assets
    ->addCssFile(Asset::new('build/admin.css')->preload()->nopush())
    ->addCssFile(Asset::new('build/admin-print.css')->htmlAttr('media', 'print'))

    ->addJsFile(Asset::new('build/admin.js')->defer())
    ->addJsFile(Asset::new('build/admin.js')->preload())
    ->addJsFile(Asset::new('build/admin.js')->htmlAttr('referrerpolicy', 'strict-origin'))

    ->addWebpackEncoreEntry(Asset::new('admin-app')->webpackEntrypointName('...'))

    // adding full Asset objects for AssetMapper entries work too, but it's
    // useless because entries can't define any property, only their name
    ->addAssetMapperEntry(Asset::new('admin'))

    ->addCssFile(Asset::new('build/admin-detail.css')->onlyOnDetail())
    ->addJsFile(Asset::new('build/admin.js')->onlyWhenCreating())
    ->addWebpackEncoreEntry(Asset::new('admin-app')->ignoreOnForm())

    // you can also define the Symfony Asset package which the asset belongs to
    ->addCssFile(Asset::new('some-path/foo.css')->package('legacy_assets'))
;

提示

字段 也可以将 CSS 和 JavaScript 资源添加到渲染的页面。阅读此节以了解如何操作。

注意

如果您想卸载 EasyAdmin 包含的默认资源,请覆盖默认的 layout.html.twig 模板并清空 head_stylesheetshead_javascript Twig 代码块。

自定义后端设计

后端的设计是用大量的 CSS 变量创建的。这使得您可以更轻松地根据自己的需求进行自定义。您将在 vendor/easycorp/easyadmin-bundle/assets/css/easyadmin-theme/variables-theme.scss 文件中找到所有变量。要覆盖其中的任何一个,请创建一个 CSS 文件并重新定义变量值

1
2
3
4
5
6
7
8
9
10
11
/* public/css/admin.css */
:root {
    /* make the backend contents as wide as the browser window */
    --body-max-width: 100%;
    /* change the background color of the <body> */
    --body-bg: #f5f5f5;
    /* make the base font size smaller */
    --font-size-base: 13px;
    /* remove all border radius to make corners straight */
    --border-radius: 0px;
}

然后,在您的仪表盘和/或资源管理中加载此 CSS 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;

#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
    // ...

    public function configureAssets(): Assets
    {
        return Assets::new()->addCssFile('css/admin.css');
    }
}

注意

由于 Bootstrap 样式的定义方式,不可能使用 CSS 变量来覆盖每个样式。有时您可能还需要覆盖某些 Sass 变量的值(这些变量在 assets/css/easyadmin-theme/variables-bootstrap.scss 文件中定义)。

CSS 选择器

每个后端页面的 <body> 元素都包含不同的 idclass 属性,以帮助您定位自己的样式。id 遵循以下模式

页面 <body> ID 属性
详情 ea-detail-<entity_name>-<entity_id>
编辑 ea-edit-<entity_name>-<entity_id>
列表 ea-index-<entity_name>
新建 ea-new-<entity_name>

例如,如果您正在编辑 User 实体的 id = 200 的元素,则该页面的 <body> 将为 <body id="easyadmin-edit-User-200" ...>

class 属性的模式不同,因为它同时应用多个 CSS 类

页面 <body> CSS 类
详情 ea-detail ea-detail-<entity_name>
编辑 ea-edit ea-edit-<entity_name>
列表 ea-index ea-index-<entity_name>
新建 ea-new ea-new-<entity_name>

例如,如果您正在显示 User 实体元素的列表,则该页面的 <body> 将为 <body class="ea index index-User" ...>

使用 Webpack 管理后端资源

EasyAdmin 使用 Webpack(通过 Symfony 的 Webpack Encore)来管理其 CSS 和 JavaScript 资源。此扩展包同时提供了所有资源的源文件和编译版本,因此您不必安装 Webpack 即可使用此扩展包。

但是,如果您想完全控制后端样式,可以使用 Webpack 集成 assets/ 目录中提供的 SCSS 和 JavaScript 源文件。唯一的注意事项是 EasyAdmin 在加载资源时尚未使用 Webpack Encore,因此您无法使用版本控制等功能。这将在未来的版本中修复。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本