Drupal 11: Node Display Mode Preview Form Using HTMX
本文将探讨如何使用 Drupal 和 HTMX 创建一个节点显示模式预览表单。首先,我们将了解什么是 Drupal 和 HTMX,以及它们如何协同工作。然后,我们将逐步构建表单,并展示如何使用 HTMX 实现实时预览。
在开始之前,我们需要了解 Drupal 和 HTMX 的基本概念。Drupal 是一个开源的内容管理系统,而 HTMX 是一个用于构建交互式 Web 应用程序的库。通过结合这两个工具,我们可以创建一个强大的表单,允许用户实时预览不同显示模式下的节点。
接下来,我们将创建一个表单,让用户输入节点 ID 和选择显示模式。表单将使用 HTMX 实时更新预览区域,展示所选节点在不同显示模式下的外观。
最后,我们将展示如何使用 HTMX 的功能,如 POST 请求和延迟触发,来优化表单的交互性和性能。
通过本文的学习,你将学会如何使用 Drupal 和 HTMX 创建一个功能强大的节点显示模式预览表单。这个表单可以帮助用户更好地了解节点在不同显示模式下的外观,提高用户体验。
让我们开始吧!
路由和配置
我们需要配置路由和表单,以确保表单可以正确访问和显示。路由配置如下:
drupal_htmx_examples_display_mode_preview_form:
path: "/htmx-examples/display-mode-preview"
defaults:
_form: '\Drupal\drupal_htmx_examples\Form\DisplayModePreviewForm'
_title: "HTMX Display Mode Preview Form"
requirements:
_permission: "access content"
这个路由配置定义了表单的路径和默认设置。用户可以通过访问 `/htmx-examples/display-mode-preview` 来访问表单。
接下来,我们将详细介绍表单的实现。
表单实现
表单的实现涉及几个关键步骤。首先,我们需要定义表单的依赖项:
-
entity_type.manager- 用于加载和管理实体类型,例如节点。 -
entity_display.repository- 用于获取实体的显示模式。
在 `buildForm()` 方法中,我们将创建表单元素并处理用户输入:
<?php
namespace Drupal\drupal_htmx_examples\Form;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Htmx\Htmx;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form to show nodes being rendered in different view modes.
*/
class DisplayModePreviewForm extends FormBase
{
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* The entity display repository service.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected EntityDisplayRepositoryInterface $entityDisplayRepository;
public static
function create(ContainerInterface $container): self
{
$instance = new static($container);
$instance->entityTypeManager = $container->get('entity_type.manager');
$instance->entityDisplayRepository = $container->get('entity_display.repository');
return $instance;
}
public
function getFormId()
{
return 'display_mode_preview_form';
}
public
function submitForm(array &$form, FormStateInterface $form_state): void
{
// Do nothing.
}
}
`buildForm()` 方法的主要步骤如下:
- 获取用户输入的节点 ID 和显示模式,如果没有输入则使用默认值。
- 创建节点 ID 输入字段。
- 加载节点的显示模式,并创建显示模式选择字段。
- 创建一个占位符,用于显示节点的预览输出。
- 如果用户输入了节点 ID,则加载该节点并使用所选显示模式进行渲染。
- 将渲染结果注入到预览输出的占位符中。
以下是 `buildForm()` 方法的完整实现:
public
function buildForm(array $form, FormStateInterface $form_state)
{
// Get the input from the user, if any is set, setting some sensible
// defaults.
$nid = $form_state->getValue('node_id', '');
$viewMode = $form_state->getValue('view_mode', 'full');
// The node ID input field.
$form['node_id'] = [
'#type' => 'number',
'#title' => $this->t('Node ID'),
'#default_value' => $nid,
];
// Load the view modes for the node.
$viewModes = $this->entityDisplayRepository->getViewModes('node');
$viewModesSelection = [];
foreach ($viewModes as $id => $mode) {
$viewModesSelection[$id] = $mode['label'];
}
// Create the view mode selection field.
$form['view_mode'] = [
'#title' => $this->t('View modes'),
'#type' => 'select',
'#empty_option' => $this->t('- Select -'),
'#options' => $viewModesSelection,
'#default_value' => $viewMode,
];
// Create a placeholder for the node output.
$form['output'] = [
'#markup' => '<div id="node-preview-output"></div>',
];
if ($nid === '') {
// If no node ID is set then return here.
return $form;
}
// Load the node using the entered ID.
$nodeStorage = $this->entityTypeManager->getStorage('node');
$node = $nodeStorage->load($nid);
if (!$node) {
// If we don't have a node (the user might have entered a node ID that
// doesn't exist) then we return here with a simple message.
$form['output'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $this->t('Node not found'),
'#attributes' => [
'id' => 'node-preview-output',
],
];
return $form;
}
// If we have a node, then render it using the selected view mode and
// inject that into the 'children' element of the output form element. This
// will render the node as the form element is rendered.
$viewBuilder = $this->entityTypeManager->getViewBuilder('node');
$renderArray = $viewBuilder->view($node, $viewMode);
$form['output'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#attributes' => [
'id' => 'node-preview-output',
],
'children' => $renderArray,
];
return $form;
}
ID 为 `node-preview-output` 的 `div` 元素用于显示节点的预览输出。当用户输入节点 ID 或选择显示模式时,HTMX 将自动更新该元素的内容。
在 `submitForm()` 方法中,我们可以处理表单提交事件。由于我们的表单主要用于预览,因此可以不做任何处理。
使用 HTMX 实现实时预览
为了实现实时预览,我们需要使用 HTMX 的功能。首先,我们将为节点 ID 和显示模式输入字段添加 HTMX 属性:
对于节点 ID 输入字段:
$form['node_id'] = [
'#type' => 'number',
'#title' => $this->t('Node ID'),
'#default_value' => $nid,
];
(new Htmx()) ->post() ->trigger('input delay:0.5s') ->target('#node-preview-output')
// Select is required to pick out the correct element from our response, which will contain the entire form.
->select('#node-preview-output') ->swap('outerHTML') ->applyTo($form['node_id']);
这里的 HTMX 属性解释如下:
-
data-hx-post- 指定 POST 请求的目标 URL。 - data-tx-trigger - 指定触发请求的事件和延迟时间。
-
data-hx-target- 指定更新的目标元素。 -
data-hx-select- 从响应中选择要更新的元素。 -
data-hs-swap- 指定更新元素的方式。
对于显示模式选择字段,我们也添加类似的 HTMX 属性:
$form['view_mode'] = [
'#title' => $this->t('View modes'),
'#type' => 'select',
'#empty_option' => $this->t('- Select -'),
'#options' => $viewModesSelection,
'#default_value' => $viewMode,
];
(new Htmx()) ->post() ->target('#node-preview-output')
// Select is required to pick out the correct element from our response, which will contain the entire form.
->select('#node-preview-output') ->swap('outerHTML') ->applyTo($form['view_mode']);
通过这些属性,当用户输入节点 ID 或选择显示模式时,HTMX 将自动发送 POST 请求,并更新 `node-preview-output` 元素的内容。
HTMX 表单示例
以下是最终生成的 HTMX 表单示例:
<div class="js-form-item form-item form-type-number js-form-type-number form-item-node-id js-form-item-node-id">
<label for="edit-node-id" class="form-item__label">Node ID</label>
<input data-hx-post="" data-hx-trigger="input delay:0.5s" data-hx-target="#node-preview-output" data-hx-select="#node-preview-output" data-drupal-selector="edit-node-id" type="number" id="edit-node-id" name="node_id" value="" step="1" class="form-number form-element form-element--type-number form-element--api-number">
</div>
<div class="js-form-item form-item form-type-select js-form-type-select form-item-view-mode js-form-item-view-mode">
<label for="edit-view-mode" class="form-item__label">View modes</label>
<select data-hx-post="" data-hx-target="#node-preview-output" data-hx-select="#node-preview-output" data-drupal-selector="edit-view-mode" id="edit-view-mode" name="view_mode" class="form-select form-element form-element--type-select">
<option value="" selected="selected">- Select -</option>
<option value="full">Full content</option>
<option value="rss">RSS</option>
<option value="search_index">Search index</option>
<option value="search_result">Search result highlighting input</option>
<option value="teaser">Teaser</option>
</select>
</div>
<div id="node-preview-output"></div>
当用户输入节点 ID 为 42 并选择显示模式为 "Teaser" 时,HTMX 将自动更新 `node-preview-output` 元素的内容,显示该节点在 "Teaser" 模式下的预览。
HTMX 在 Drupal 中的使用可以大大提高表单的交互性和性能。通过使用 HTMX 的功能,我们可以实现实时预览,减少页面刷新,提高用户体验。
同时,HTMX 还可以与 Drupal 的 CSS 和 JavaScript 集成,进一步增强表单的样式和功能。
以下是一个演示图片,展示了使用 HTMX 实现的节点预览表单:

在 Drupal 中使用 HTMX 可以为用户提供更好的交互体验,同时也提高了开发效率。通过结合这两个工具,我们可以创建出功能强大、交互性好的 Web 应用程序。
- Drupal 的表单系统可以与 HTMX 无缝集成,实现实时更新和交互。
- HTMX 的功能可以帮助我们减少页面刷新,提高性能。
通过本文的学习,你应该能够掌握如何使用 Drupal 和 HTMX 创建一个节点显示模式预览表单。这个表单可以帮助用户更好地了解节点在不同显示模式下的外观,提高用户体验。
希望本文对你有所帮助!
### 说明: 1. **标题标签替换**:将所有的 `h1` 和 `h2` 标签替换为 `h3` 标签,以满足标题使用 `h3` 标签的要求。 2. **标签闭合检查**:检查并确保所有 HTML 标签都正确关闭,避免出现未闭合的标签。 3. **内容调整**:未对内容进行实质性修改,仅对 HTML 结构进行了清洗和优化。?>

