Entrada
Saludos a colegas. Este artículo es el tercer y último artículo de una serie de artículos sobre componentes web. Los primeros dos artículos están disponibles en:
Componentes web. Parte 1: Elementos personalizadosComponentes web Parte 2: Shadow DOMEste artículo hablará sobre el elemento <template> y también sobre las importaciones HTML.
Elemento de plantillas HTML
El elemento <template> es una herramienta que le permite almacenar contenido en el lado del cliente sin mostrarlo en la página, pero con la capacidad de mostrarlo durante la ejecución a través de JavaScript.
Al analizar una página, el contenido de un elemento se procesa únicamente en términos de validación de contenido, pero sin representarlo (de acuerdo con la especificación, este elemento no representa nada al representar). El contenido del elemento se puede clonar y pegar en el documento desde scripts, que se utilizan tanto de forma independiente para la estandarización como al crear componentes web.
Contenido <plantilla>
El contenido de <template>, así como a cualquier nodo que no tenga un contexto de navegador, no aplica ningún requisito de cumplimiento, excepto los requisitos para la corrección de la sintaxis HTML y XML. Esto significa que en el contenido de la plantilla, por ejemplo, puede especificar el elemento img sin especificar el valor de los atributos src y alt, por lo tanto:
<template> <div> <img src="{{src}}" alt="{{alt}}"> </div> </template>
sin embargo, fuera del elemento <template>, dicha sintaxis no es válida. En este caso, omitir la etiqueta de cierre </div> sería una violación de la sintaxis HTML y no es válido para el contenido de <template>.
Todos los elementos especificados dentro de la etiqueta <template> en el código html no son sus hijos.
Los navegadores al crear un elemento <template> crean un DocumentFragment cuyo documento es el llamado el documento propietario del contenido de la plantilla apropiado, determinado por este algoritmo , el documento en el que se especifica <template> e indica el valor de la propiedad .content creada por DocumentFragment.
Es decir, la propiedad .content del elemento de plantilla contiene un DocumentFragment, y los elementos que se especificaron en el código html dentro de las etiquetas <template> son elementos secundarios de este DocumentFragment.
En este caso, el elemento <template>, como cualquier otro, se puede agregar con elementos secundarios ( appendChild () ), pero esto se considerará una violación del modelo de contenido de la plantilla.
Plantilla de clonación
Al clonar el contenido de una plantilla, es importante recordar que el primer argumento para .cloneNode ([deep])
o el segundo en .importNode (externalNode, deep) debe transferirse (de acuerdo con la especificación, si no se pasa el argumento, no se debe ejecutar más).
Por cierto, sí, a pesar de que la mayoría de los ejemplos usan .cloneNode (), también es posible usar .importNode (). La única diferencia es cuando el documento se actualiza (para .cloneNode () - después de llamar a appendChild (); para .importNode () - después de la clonación).
Muéstrame el código ©
Usar plantillas es realmente muy simple. Continuaré con el ejemplo de los componentes de la pestaña, con el código del cual trabajé en los ejemplos de artículos anteriores.
Comenzaré creando dos elementos <template> en el marcado html y transfiriendo el marcado en ellos que estaba en el método .render () de las clases TabNavigationItem y TabContentItem (también cambié algunos estilos, pero esto no afecta la funcionalidad):
<template id="tab-nav"> <style> :host{ padding: 10px; background-color: rgb(81,180,186); transition: background-color 1s; text-align: center; } :host-context(.active) { background-color: rgb(93, 209, 216); } a{ text-decoration: none; color: rgb(3,32,40); } </style> <a href="#${this._target}"><slot></slot></a> </template>
y:
<template id="tab-content"> <style> :host { display: none; padding: 20px; width: 100%; background-color: rgb(255,212,201); } :host-context(.active){ display: block; } </style> <div><slot></slot></div> </template>
En el constructor de cada clase, guardaré la propiedad de la plantilla. Para TabNavigationItem, esto será:
this.template = document.getElementById('tab-nav');
a para TabContentItem:
this.template = document.getElementById('tab-content');
En el método render () de cada una de estas clases, agregaré el siguiente código, después de eliminar la entrada .innerHTML:
const content = this.template.content.cloneNode(true); this.shadowRoot.appendChild(content);
El código resultante se puede encontrar aquí.
En este ejemplo, ambas plantillas se especifican en html, que parece engorroso y no zumbido. Esto nos lleva suavemente al tema:
Importaciones HTML
Las importaciones son documentos HTML que están conectados como recursos externos por otro documento HTML. El sistema de relaciones entre documentos está bien descrito en el borrador de la especificación y no es el tema de este artículo.
El esquema general es visible en la imagen:

.
Para implementar las importaciones, se agregó un nuevo tipo a los tipos de enlace HTML (valores del atributo rel).
La palabra de importación especificada en el valor del atributo rel del elemento <link> crea un enlace al recurso importado (el tipo predeterminado del recurso es text / html).
El elemento <link> puede tener un atributo asíncrono.
Las extensiones ofrecidas por el borrador de especificaciones se ofrecen en la API HTMLLinkElement: se agrega una propiedad de importación de solo lectura que contiene el documento importado.
Una propiedad puede contener nulo en dos casos: cuando <link> no representa importación o <link> no está en el documento.
La especificación establece por separado que siempre debe devolverse el mismo objeto.
En el contexto de las importaciones, existe un denominado documento maestro, que es el documento que importa recursos al mismo tiempo sin ser el recurso importado de otra persona.
ContentSecurityPolicy de dicho documento debería limitar todas las importaciones. Por lo tanto, si el campo de encabezado de seguridad de contenido está configurado para importar, el navegador debe aplicar la política del documento maestro al documento importado.
En la practica
Para el componente de pestaña, creo una carpeta de plantillas. En él, crearé dos archivos en los que transferiré el marcado del componente.
<template id="tab-content"> <style> :host { display: none; padding: 20px; width: 100%; background-color: rgb(255,212,201); } :host-context(.active){ display: block; } </style> <div><slot></slot></div> </template> <template id="tab-nav"> <style> :host{ padding: 10px; background-color: rgb(81,180,186); transition: background-color 1s; text-align: center; } :host-context(.active) { background-color: rgb(93, 209, 216); } a{ text-decoration: none; color: rgb(3,32,40); } </style> <a href="#${this._target}"><slot></slot></a> </template>
En el <head> del archivo index.html, importo las plantillas:
<link rel="import" href="templates/tab-nav.html" id="tab-nav"> <link rel="import" href="templates/tab-content.html" id="tab-content">
Agrego atributos de identificación a los elementos <link>, ya que tendré que acceder a ellos desde js.
Ahora, en los constructores de las clases TabNavigationItem y TabContentItem, para obtener el documento de plantilla, solo necesito encontrar el elemento <link> correspondiente y recurrir a su propiedad de importación, después de lo cual buscaré la plantilla que ya está en el documento importado:
class TabNavigationItem extends HTMLElement { constructor() { super(); this._target = null; this.attachShadow({mode: 'open'}); const templateImport = document.getElementById('tab-nav').import; this.template = templateImport.getElementById('tab-nav'); }
La versión final se puede tomar aquí .
Sobre soporte
Soporte para plantillas HTML: Edge c 16, Firefox c 59, Chrome c 49, Safari c 11.
Con soporte de importación más triste: Chrome c 49.
Por lo tanto, los ejemplos de este artículo solo se pueden ver en el último Chrome.
Hay polifilos:
Componentes webProyecto de polímeroLea más sobre plantillas e importaciones:
Especificación HTMLEspecificación HTML5Importación de borradores de especificaciones HTMLEso es todo, gracias por mirar,
Tanya