9.4 高级渲染数组模式

HTML 属性

你能通过渲染数组设置 HTML 属性(例如 ID 和 Class)。这些属性会被传递到 Twig 模板,也允许 themer 添加和覆盖这些值。为了做这个,向渲染数组添加 #attributes 变量。数组的键是属性,值是属性的值。

$element = [
  '#type' => 'my_element',
  '#config_one' => 'blue',
];

$element['#attributes'] = [
  'id' => 'my_blue_element_1',
  'class' => ['my-element','blue'],
];

 

这允许辅助内容区中的预处理钩子对其进行覆盖 —– $variables[‘attributes’] 被 theme.inc 内的 template_process() 函数创建,template_process() 运行于所有的渲染数组。$variables[‘attributes’] 是一个副本,原始值存储在 $variables[‘element’][‘#attributes’] 内,但这个原始值基本不怎么用。

function hook_preprocess_my_element(&$variables) {
  $variables['attributes']['id'] = 'my_blue_element_altered_id';
}

 

之后你可以在 Twig 模板中使用这些值:(见辅助内容区)

在预处理函数作用于 attributes  变量之后,他们被转变为对象,以便方便在 Twig 中修改和输出。这个处理由  ThemeManager.php 中的 render() 完成。

<div {{ attributes }}>
{{ element }}
</div>

 

包装器(#theme_wrapper)和容器

你能用 div 包装你的元素和使用之前的模式向这个包装器追加 class。通过向渲染数组添加 #theme_wrappers 实现这个。最常见的包装器类型是输出属性的一个容器。

$element = [
  '#type' => 'my_element',
  '#config_one' => 'blue',
  '#theme_wrappers' => [
    'container' => [
      '#attributes' => [
        'class' => ['my-wrapper-class']
      ],
    ],
  ],
];

 

对应的容器模板文件象这样:
container.html.twig

{%
  set classes = [
    has_parent ? 'js-form-wrapper',
    has_parent ? 'form-wrapper',
  ]
%}
<div{{ attributes.addClass(classes) }}>{{ children }}</div>

 

探讨元素渲染数组流程

Drupal 7 支持分支系统的方式渲染元素。Drupal 8 希望简化这个,但很多旧的系统仍然残留。本课,我们跟随一个路径,这是核心内使用、推荐的一种模式。Drupal 核心仍然混杂使用所有的路径。

Element Plugin / pre_render / Twig pattern (见附图)

选择此模式背后的原因是保持与 Drupal 8 的一致,同时又不失灵活性。坚持面向对象模式,我们将所有元素定义为插件。“把所有的元素信息包含在一个插件文件内”符合 Drupal 8 对插件和类的结构化形式。所有元素在它们到达模板之前允许其他模块使用 hook_preprocess_hook 对其覆盖。因此我们保持了使用覆盖的能力。

与核心的差异

这种模式与核心之间的主要区别是多数核心也使用了 template_preprocess_hook,这似乎与 #pre_render 冗余。因为系统使用的一些怪癖,有些核心同时使用了这两种方法。这些怪癖可能增添几分优雅,但带来的代价是增加了复杂度,把逻辑分离在多个地方。

d8RecommendedRenderPath

评论 (写第一个评论)