设计
后端的设计已为任何类型的应用程序做好准备。它使用 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-pin
、ic:baseline-calendar-month
等),这通常在 Symfony UX Icons 中使用。
如果您的所有图标都使用一个共同的前缀(例如,使用 Tabler 图标时为 tabler:
),请将其传递给 useCustomIconSet()
方法
1
return Assets::new()->useCustomIconSet('tabler');
现在,tabler:
前缀将自动添加到您的所有自定义图标名称中。这样,您可以使用诸如 user
和 file
之类的名称,而不是 tabler:user
和 tabler: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()
方法仅适用于在 index
和 detail
页面上显示的字段。阅读下一节以了解如何自定义 new
和 edit
页面中的字段,这些页面使用 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'))
;
注意
如果您想卸载 EasyAdmin 包含的默认资源,请覆盖默认的 layout.html.twig
模板并清空 head_stylesheets
和 head_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>
元素都包含不同的 id
和 class
属性,以帮助您定位自己的样式。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,因此您无法使用版本控制等功能。这将在未来的版本中修复。