Desarrollo de un bloque con opciones
Este tutorial se basa en la guía de Edge Delivery Services y del editor universal que incluye el proceso de añadir opciones de bloque a otro bloque. Al definir las opciones de bloque, puede personalizar el aspecto y la funcionalidad de un bloque, lo que permite diferentes variaciones para adaptarlas a diversas necesidades de contenido. Esto permite una mayor flexibilidad y reutilización dentro del sistema de diseño del sitio.
En este tutorial, añadirá opciones de bloque al bloque Teaser, lo que permite a los autores elegir entre dos opciones de visualización: Predeterminado y En paralelo. La opción Predeterminado muestra la imagen encima y detrás del texto, mientras que la opción En paralelo muestra la imagen y el texto uno al lado del otro.
Casos de uso comunes
Los casos de uso comunes para usar Opciones de bloque en el desarrollo de Edge Delivery Services y Editor universal incluyen, entre otros:
- Variaciones de diseño: Cambiar fácilmente entre diseños. Por ejemplo, horizontal vs. vertical o cuadrícula vs. lista.
- Variaciones de estilo: Cambie fácilmente entre temas o tratamientos visuales. Por ejemplo, modo claro u oscuro, o texto grande frente a texto pequeño.
- Control de visualización de contenido: alternar visibilidad de elementos o cambiar entre estilos de contenido (compacto vs. detallado).
Estas opciones ofrecen flexibilidad y eficiencia para crear bloques dinámicos y adaptables.
Este tutorial muestra el caso de uso de las variaciones de diseño, en el que el bloque Teaser se puede mostrar en dos diseños diferentes: Predeterminado y En paralelo.
Modelo de bloque
Para añadir opciones de bloque al bloque Teaser, abra su fragmento JSON en /block/teaser/_teaser.json
y añada un nuevo campo a la definición del modelo. Este campo establece su propiedad name
en classes
un campo protegido utilizado por AEM para almacenar opciones de bloque, que se aplican al bloque HTML de Edge Delivery Services.
Configuraciones de campo
Las pestañas siguientes ilustran varias formas de configurar las opciones de bloque en el modelo de bloques, incluida la selección única con una sola clase CSS, la selección única con varias clases CSS y la selección múltiple con varias clases CSS. Este tutorial implementa el método más sencillo utilizado en seleccionar con una sola clase CSS.
Este tutorial muestra cómo utilizar un tipo de entrada select
(desplegable) para permitir que los autores elijan una sola opción de bloque, que luego se aplica como una sola clase CSS correspondiente.
Modelo de bloque
La opción Predeterminado está representada por una cadena vacía (""
), mientras que la opción En paralelo usa "side-by-side"
. El nombre y valor de la opción no tienen por qué ser iguales, pero el valor determina las clases CSS aplicadas al HTML del bloque. Por ejemplo, el valor de la opción en paralelo podría ser layout-10
en lugar de side-by-side
. Sin embargo, es mejor utilizar nombres semánticamente significativos para las clases CSS, lo que garantiza la claridad y coherencia en los valores de las opciones.
[/blocks/teaser/_teaser.json]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
code language-none h-4 h-8 h-9-18 |
---|
|
Bloquear HTML
Cuando el autor selecciona una opción, el valor correspondiente se añade como clase CSS a la HTML del bloque:
-
Si se selecciona Predeterminado:
code language-html <div class="block teaser"> <!-- Block content here --> </div>
-
Si se selecciona en paralelo:
code language-html <div class="block teaser side-by-side"> <!-- Block content here --> </div>
Esto permite aplicar diferentes estilos y JavaScript condicional según la apertura elegida.
Este método no se usa en este tutorial, pero ilustra un método alternativo y opciones de bloque avanzadas.
El tipo de entrada select
permite a los autores elegir una sola opción de bloque, que puede asignarse opcionalmente a varias clases CSS. Para conseguirlo, enumere las clases CSS como valores delimitados por espacios.
Modelo de bloque
Por ejemplo, la opción en paralelo puede admitir variaciones en las que la imagen aparece a la izquierda (side-by-side left
) o a la derecha (side-by-side right
).
[/blocks/teaser/_teaser.json]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
code language-none h-4 h-8 h-9-21 |
---|
|
Bloquear HTML
Cuando el autor selecciona una opción, el valor correspondiente se aplica como un conjunto de clases CSS separadas por espacios en la HTML del bloque:
-
Si se selecciona Predeterminado:
code language-html <div class="block teaser"> <!-- Block content here --> </div>
-
Si se selecciona En paralelo con la imagen a la izquierda:
code language-html <div class="block teaser side-by-side left"> <!-- Block content here --> </div>
-
Si se selecciona En paralelo con la imagen a la derecha:
code language-html <div class="block teaser side-by-side right"> <!-- Block content here --> </div>
Esto permite aplicar diferentes estilos y JavaScript condicional según la opción elegida.
Este método no se usa en este tutorial, pero ilustra un método alternativo y opciones de bloque avanzadas.
El tipo de entrada de "component": "multiselect"
permite al autor seleccionar varias opciones simultáneamente. Esto permite permutaciones complejas del aspecto del bloque al combinar varias opciones de diseño.
Modelo de bloque
Por ejemplo, En paralelo, Imagen a la izquierda e Imagen a la derecha pueden admitir variaciones en las que la imagen se coloque a la izquierda (side-by-side left
) o a la derecha (side-by-side right
).
[/blocks/teaser/_teaser.json]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
code language-none h-4 h-6 h-8 h-10-21 |
---|
|
Bloquear HTML
Cuando el autor selecciona varias opciones, los valores correspondientes se aplican como clases CSS separadas por espacios en la HTML del bloque:
-
Si se seleccionan En paralelo e Imagen a la izquierda:
code language-none h-1 <div class="block teaser side-by-side left"> <!-- Block content here --> </div>
-
Si se seleccionan En paralelo e Imagen a la derecha:
code language-none h-1 <div class="block teaser side-by-side right"> <!-- Block content here --> </div>
Aunque la selección múltiple ofrece flexibilidad, introduce complejidad en la administración de permutaciones de diseño. Sin restricciones, las selecciones conflictivas pueden provocar experiencias rotas o fuera de la marca.
Por ejemplo:
- Imagen a la izquierda o Imagen a la derecha sin seleccionar En paralelo los aplica implícitamente a Predeterminado, que siempre establece la imagen como fondo, por lo que la alineación izquierda y derecha son irrelevantes.
- Seleccionar tanto Imagen a la izquierda como Imagen a la derecha es contradictorio.
- Seleccionar En paralelo sin Imagen a la izquierda o Imagen a la derecha puede considerarse ambiguo, ya que la posición de la imagen no está especificada.
Para evitar problemas y confusión de autores al utilizar la selección múltiple, asegúrese de que las opciones estén bien planificadas y que todas las permutaciones se hayan probado. La selección múltiple funciona mejor para mejoras sencillas y sin conflictos, como "grande" o "resaltado", en lugar de para opciones que modifican el diseño.
Este método no se usa en este tutorial, pero ilustra un método alternativo y opciones de bloque avanzadas.
Las opciones de bloque se pueden establecer como predeterminadas al añadir una nueva instancia de bloque a una página en el editor universal. Esto se hace estableciendo el valor predeterminado de la propiedad classes
en la definición del bloque.
Definición de bloque
En el ejemplo siguiente, la opción predeterminada se establece en En paralelo al asignar la propiedad value
del campo classes
a side-by-side
. La entrada de la opción de bloque correspondiente en el modelo de bloque es opcional.
También puede definir varias entradas para el mismo bloque, cada una con un nombre y una clase diferentes. Esto permite al Editor universal mostrar distintas entradas de bloque, cada una preconfigurada con una opción de bloque específica. Aunque estos aparecen como bloques independientes en el editor, la base de código contiene un solo bloque que se procesa dinámicamente en función de la opción seleccionada.
[/blocks/teaser/_teaser.json]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
code language-none h-12 |
---|
|
Configuración de campo para este tutorial
En este tutorial, usaremos el enfoque de seleccionar con una sola clase CSS descrito arriba en la primera pestaña, que permite dos opciones de bloque discreto: Predeterminado y En paralelo.
En la definición del modelo dentro del fragmento JSON del bloque, añada un solo campo de selección para las opciones del bloque. Este campo permite a los autores elegir entre el diseño predeterminado y un diseño en paralelo.
[/blocks/teaser/_teaser.json]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
{
"definitions": [...],
"models": [
{
"id": "teaser",
"fields": [
{
"component": "select",
"name": "classes",
"value": "",
"label": "Teaser options",
"description": "",
"valueType": "string",
"options": [
{
"name": "Default",
"value": ""
},
{
"name": "Side-by-side",
"value": "side-by-side"
}
]
},
{
"component": "reference",
"valueType": "string",
"name": "image",
"label": "Image",
"multi": false
},
{
"component": "text",
"valueType": "string",
"name": "imageAlt",
"label": "Image alt text",
"required": true
},
{
"component": "richtext",
"name": "textContent_text",
"label": "Text",
"valueType": "string",
"required": true
},
{
"component": "aem-content",
"name": "textContent_cta",
"label": "CTA",
"valueType": "string"
},
{
"component": "text",
"name": "textContent_ctaText",
"label": "CTA label",
"valueType": "string"
}
]
}
],
"filters": []
}
Actualizar bloque en el Editor universal
Para que la entrada de opciones de bloque actualizadas esté disponible en el editor universal, implemente los cambios de código JSON en GitHub, cree una nueva página, añada y cree el bloque Teaser con la opción En paralelo y, a continuación, publique la página para previsualizarla. Una vez publicada, cargue la página en el entorno de desarrollo local para codificarla.
Insertar cambios en GitHub
Para que la entrada de opciones de bloque actualizadas esté disponible en el Editor universal para establecer opciones de bloque y desarrollar con la HTML resultante, el proyecto debe estar vinculado y los cambios deben insertarse en una rama de GitHub, en este caso, la rama block-options
.
# ~/Code/aem-wknd-eds-ue
# Lint the changes to catch any syntax errors
$ npm run lint
$ git add .
$ git commit -m "Add Teaser block option to JSON file so it is available in Universal Editor"
$ git push origin teaser
Creación de una página de prueba
En el servicio de AEM Author, cree una nueva página para añadir el bloque Teaser para desarrollo. Siguiendo las convenciones en el capítulo Crear un bloque del tutorial para desarrolladores de Edge Delivery Services y editor universal, cree una página de prueba en branches
, y nómbrela como la rama Git en la que esté trabajando (en este caso, block-options
).
Crear el formulario
Edite la nueva página Opciones de bloque en el Editor universal y añada el bloque Teaser. Asegúrese de añadir el parámetro de consulta ?ref=block-options
a la dirección URL para cargar la página con el código de la rama de GitHub block-options
,
El cuadro de diálogo de bloque ahora incluye la lista desplegable de Opciones de teaser con Opciones predeterminadas y selecciones en paralelo. Elija En paralelo y complete el resto de la creación de contenido.
Opcionalmente, añada dos bloques de teaser: uno establecido en predeterminado y el otro en paralelo. Esto le permite obtener una vista previa de ambas opciones en paralelo durante el desarrollo y garantiza que la implementación En paralelo no afecte a la opción Predeterminado.
Publicar en vista previa
Una vez añadido el bloque Teaser a la página, publique la página para obtener una vista previa con el botón Publicar y elija Publicar en Vista previa en el Editor universal.
Bloquear HTML
Para comenzar el desarrollo del bloque, comience por revisar la estructura DOM expuesta en la vista previa de Edge Delivery Services. El DOM se mejora con JavaScript y se diseña con CSS, lo que proporciona la base para crear y personalizar el bloque.
El siguiente es el DOM del bloque Teaser, con la opción de bloque En paralelo seleccionada, que es el destino a decorar usando JavaScript y CSS.
code language-none h-7 |
---|
|
Para encontrar el DOM para decorar, abra la página con el bloque en su entorno de desarrollo local, seleccione el bloque con las herramientas para desarrolladores del explorador web e inspeccione el DOM. Esto le permitirá identificar los elementos relevantes para decorar.
Bloquear CSS
Edite blocks/teaser/teaser.css
para añadir estilos CSS específicos para la opción En paralelo. Este archivo contiene el CSS predeterminado para el bloque.
Para modificar los estilos de la opción Side-by-Side, añada una nueva regla CSS de ámbito en el archivo teaser.css
que identifica los bloques de teaser configurados con la clase side-by-side
.
.block.teaser.side-by-side { ... }
También puede utilizar el anidamiento CSS para una versión más concisa:
.block.teaser {
... Default teaser block styles ...
&.side-by-side {
... Side-by-side teaser block styles ...
}
}
En la regla &.side-by-side
, añada las propiedades CSS necesarias para aplicar estilo al bloque cuando se aplique la clase side-by-side
.
Un enfoque común es restablecer los estilos predeterminados aplicando all: initial
a los selectores compartidos y, a continuación, añadiendo los estilos necesarios para la variante side-by-side
. Si la mayoría de los estilos se comparten entre opciones, puede que sea más fácil anular propiedades específicas. Sin embargo, si varios selectores necesitan cambios, restablecer todos los estilos y volver a aplicar solo los necesarios puede hacer que el código sea más claro y fácil de mantener.
[/blocks/teaser/teaser.css]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
/* /blocks/teaser/teaser.css */
/* Scope each selector in the block with `.block.teaser` to avoid accidental conflicts outside the block */
.block.teaser {
animation: teaser-fade-in 1s;
position: relative;
width: 1600px;
max-width: 100vw;
left: 50%;
transform: translateX(-50%);
height: 500px;
overflow: hidden;
/* The teaser image */
.image-wrapper {
position: absolute;
z-index: -1;
inset: 0;
box-sizing: border-box;
overflow: hidden;
.image {
object-fit: cover;
object-position: center;
width: 100%;
height: 100%;
transform: scale(1);
transition: transform 0.6s ease-in-out;
.zoom {
transform: scale(1.1);
}
}
}
/* The teaser text content */
.content {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
background: var(--background-color);
padding: 1.5rem 1.5rem 1rem;
width: 80vw;
max-width: 1200px;
.title {
font-size: var(--heading-font-size-xl);
margin: 0;
}
.title::after {
border-bottom: 0;
}
p {
font-size: var(--body-font-size-s);
margin-bottom: 1rem;
animation: teaser-fade-in .6s;
}
p.terms-and-conditions {
font-size: var(--body-font-size-xs);
color: var(--secondary-color);
padding: .5rem 1rem;
font-style: italic;
border: solid var(--light-color);
border-width: 0 0 0 10px;
}
/* Add underlines to links in the text */
a:hover {
text-decoration: underline;
}
/* Add specific spacing to buttons. These button CSS classes are automatically added by Edge Delivery Services. */
.button-container {
margin: 0;
padding: 0;
.button {
background-color: var(--primary-color);
border-radius: 0;
color: var(--dark-color);
font-size: var(--body-font-size-xs);
font-weight: bold;
padding: 1em 2.5em;
margin: 0;
text-transform: uppercase;
}
}
}
/**
* Add styling for the side-by-side variant
**/
/* This evaluates to .block.teaser.side-by-side */
&.side-by-side {
/* Since this default teaser option doesn't have a style (such as `.default`), we use `all: initial` to reset styles rather than overriding individual styles. */
all: initial;
display: flex;
margin: auto;
max-width: 900px;
.image-wrapper {
all: initial;
flex: 2;
overflow: hidden;
* {
height: 100%;
}
.image {
object-fit: cover;
object-position: center;
width: 100%;
height: 100%;
transform: scale(1);
transition: transform 0.6s ease-in-out;
&.zoom {
/* This option has a different zoom level than the default */
transform: scale(1.5);
}
}
}
.content {
all: initial;
flex: 1;
background-color: var(--light-color);
padding: 3.5em 2em 2em;
font-size: var(--body-font-size-s);
font-family: var(--body-font-family);
text-align: justify;
text-justify: newspaper;
hyphens: auto;
p.terms-and-conditions {
border: solid var(--text-color);
border-width: 0;
padding-left: 0;
text-align: left;
}
}
/* Media query for mobile devices */
@media (width <= 900px) {
flex-direction: column; /* Stack elements vertically on mobile */
}
}
}
/** Animations
Scope the @keyframes to the block (teaser) to avoid accidental conflicts outside the block
Global @keyframes can defines in styles/styles.css and used in this file.
**/
@keyframes teaser-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
Bloquear JavaScript
La identificación de las opciones activas para el bloque es sencilla mediante la comprobación de las clases aplicadas al elemento de bloque. En este ejemplo, necesitamos ajustar dónde se aplican los estilos .image-wrapper
en función de la opción activa.
La función getOptions
devuelve una matriz de clases aplicadas al bloque, excluyendo block
y teaser
(ya que todos los bloques tienen la clase block
y todos los bloques Teaser tienen la clase teaser
). El resto de las clases de la matriz indican las opciones activas. Si la matriz está vacía, se aplica la opción predeterminada.
function getOptions(block) {
// Get the block's classes, excluding 'block' and 'teaser'; anything remaining is a block option.
return [...block.classList].filter((c) => !['block', 'teaser'].includes(c));
}
Esta lista de opciones se puede utilizar para ejecutar de forma condicional la lógica personalizada en el JavaScript del bloque:
if (getOptions(block).includes('side-by-side')) {
/* For side-by-side teaser, add the image-wrapper to a higher-level div to support CSS */
block.querySelector(':scope > div:first-child').classList.add('image-wrapper');
} else if (!getOptions(block)) {
/* For the default option, add the image-wrapper to the picture element to support CSS */
block.querySelector('picture').classList.add('image-wrapper');
}
El archivo JavaScript completo actualizado para el bloque de teaser con las opciones Predeterminado y En paralelo es el siguiente:
[/blocks/teaser/teaser.js]{class="badge neutral" title="Nombre de archivo del ejemplo de código siguiente."}
/* /blocks/teaser/teaser.js */
/**
* Block options are applied as classes to the block's DOM element
* alongside the `block` and `<block-name>` classes.
*
* @param {HTMLElement} block represents the block's DOM element/tree
*/
function getOptions(block) {
// Get the block's classes, excluding 'block' and 'teaser'.
return [...block.classList].filter((c) => !['block', 'teaser'].includes(c));
}
/**
* Adds a zoom effect to the image using event listeners.
*
* When the CTA button is hovered over, the image zooms in.
*
* @param {HTMLElement} block represents the block's DOM tree
*/
function addEventListeners(block) {
block.querySelector('.button').addEventListener('mouseover', () => {
block.querySelector('.image').classList.add('zoom');
});
block.querySelector('.button').addEventListener('mouseout', () => {
block.querySelector('.image').classList.remove('zoom');
});
}
/**
* Entry point to the block's JavaScript.
* Must be exported as default and accept a block's DOM element.
* This function is called by the project's style.js, passing the block's element.
*
* @param {HTMLElement} block represents the block's DOM element/tree
*/
export default function decorate(block) {
/* Common treatments for all options */
block.querySelector(':scope > div:last-child').classList.add('content');
block.querySelector('h1,h2,h3,h4,h5,h6').classList.add('title');
block.querySelector('img').classList.add('image');
// Process each paragraph and mark it as text or terms-and-conditions
block.querySelectorAll('p').forEach((p) => {
const innerHTML = p.innerHTML?.trim();
if (innerHTML?.startsWith('Terms and conditions:')) {
p.classList.add('terms-and-conditions');
}
});
/* Conditional treatments for specific options */
if (getOptions(block).includes('side-by-side')) {
/* For side-by-side teaser, add the image-wrapper to a higher-level div to support CSS */
block.querySelector(':scope > div:first-child').classList.add('image-wrapper');
} else if (!getOptions(block)) {
/* For the default option, add the image-wrapper to the picture element to support CSS */
block.querySelector('picture').classList.add('image-wrapper');
}
addEventListeners(block);
}
Previsualización de desarrollo
A medida que se añaden CSS y JavaScript, el entorno de desarrollo local de la CLI de AEM vuelve a cargar los cambios, lo que permite una visualización rápida y sencilla del impacto del código en el bloque. Pase el ratón sobre el CTA y compruebe que la imagen del teaser se amplía y reduce.
Limpie su código
Asegúrese de limpiar con frecuencia los cambios de su código para mantenerlo limpio y consistente. La limpieza regular ayuda a detectar los problemas de forma temprana, lo que reduce el tiempo de desarrollo general. Recuerde, no puede combinar su trabajo de desarrollo en la rama main
hasta que se resuelvan todos los problemas de vinculación.
# ~/Code/aem-wknd-eds-ue
$ npm run lint
Vista previa en el Editor universal
Para ver los cambios en el editor universal de AEM, añádalos, confírmelos y envíelos a la rama del repositorio de Git utilizada por el editor universal. De esta manera se garantiza que la implementación de bloques no interrumpa la experiencia de creación.
# ~/Code/aem-wknd-eds-ue
$ git add .
$ git commit -m "CSS and JavaScript implementation for Teaser block option Side-by-side"
# JSON files are compiled automatically and added to the commit via a Husky pre-commit hook
$ git push origin block-options
Ahora, los cambios están visibles en el Editor universal al usar el parámetro de consulta ?ref=block-options
.
Enhorabuena.
Ahora ha explorado las opciones de bloques en Edge Delivery Services y el Editor universal, lo que le ofrece las herramientas para personalizar y optimizar la edición de contenido con una mayor flexibilidad. Empiece a aplicar estas opciones en sus proyectos para mejorar la eficacia y mantener la coherencia.
Para obtener más prácticas recomendadas y técnicas avanzadas, consulte la documentación del Editor universal.