Entrada
Saudações aos colegas. Este artigo é o terceiro e último artigo de uma série de artigos sobre componentes da Web. Os dois primeiros artigos estão disponíveis em:
Componentes da Web. Parte 1: Elementos personalizadosComponentes da Web Parte 2: sombra DOMEste artigo falará sobre o elemento <template> e também sobre importações de HTML.
Elemento de modelos HTML
O elemento <template> é uma ferramenta que permite armazenar conteúdo no lado do cliente sem renderizá-lo na página, mas com a capacidade de exibi-lo durante a execução por meio de JavaScript.
Ao analisar uma página, o conteúdo de um elemento é processado exclusivamente em termos de validação de conteúdo, mas sem sua renderização (de acordo com a especificação, esse elemento não representa nada ao renderizar). O conteúdo do elemento pode ser clonado e colado no documento a partir de scripts, que são usados independentemente para padronização e ao criar componentes da Web.
Conteúdo <modelo>
O conteúdo do <template>, bem como para qualquer nó que não tenha um contexto de navegador, não aplica nenhum requisito de conformidade, exceto os requisitos para a correção da sintaxe HTML e XML. Isso significa que, no conteúdo do modelo, por exemplo, você pode especificar o elemento img sem especificar o valor dos atributos src e alt, assim:
<template> <div> <img src="{{src}}" alt="{{alt}}"> </div> </template>
no entanto, fora do elemento <template>, essa sintaxe não é válida. Nesse caso, pular a tag de fechamento </div> seria uma violação da sintaxe HTML e não é válido para o conteúdo de <template>.
Todos os elementos especificados dentro da tag <template> no código html não são seus filhos.
Os navegadores ao criar um elemento <template> criam um DocumentFragment cujo documento é o chamado documento apropriado do proprietário do conteúdo do modelo, determinado por esse algoritmo , o documento no qual <template> é especificado e indica o valor da propriedade .content criada pelo DocumentFragment.
Ou seja, a propriedade .content do elemento template contém um DocumentFragment, e os elementos que foram especificados no código html nas tags <template> são filhos desse DocumentFragment.
Nesse caso, o elemento <template>, como qualquer outro, pode ser adicionado com elementos filho ( appendChild () ), mas isso será considerado uma violação do modelo de conteúdo do modelo.
Modelo de clonagem
Ao clonar o conteúdo de um modelo, é importante lembrar que o primeiro argumento para .cloneNode ([deep])
ou o segundo em .importNode (externalNode, deep) deve ser transferido (de acordo com a especificação, se o argumento não for passado, outra execução não deverá ocorrer).
A propósito, sim, apesar do fato de a maioria dos exemplos usar .cloneNode (), também é possível usar .importNode (). A única diferença é quando o documento é atualizado (para .cloneNode () - após chamar appendChild (); para .importNode () - após clonagem).
Mostre-me o código ©
Usar modelos é realmente muito simples. Vou continuar o exemplo dos componentes da guia, com o código do qual trabalhei nos exemplos de artigos anteriores.
Começarei criando dois elementos <template> na marcação html e transferindo a marcação nos mesmos que estavam no método .render () das classes TabNavigationItem e TabContentItem (também alterei alguns estilos, mas isso não afeta a funcionalidade):
<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>
e:
<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>
No construtor de cada classe, salvarei a propriedade do modelo. Para TabNavigationItem, será:
this.template = document.getElementById('tab-nav');
a para TabContentItem:
this.template = document.getElementById('tab-content');
No método render () de cada uma dessas classes, adicionarei o seguinte código, após excluir a entrada .innerHTML:
const content = this.template.content.cloneNode(true); this.shadowRoot.appendChild(content);
O código resultante pode ser encontrado aqui.
Neste exemplo, os dois modelos são especificados em html, que parece complicado e não é movimentado. Isso nos leva sem problemas ao tópico:
Importações HTML
As importações são documentos HTML que são conectados como recursos externos por outro documento HTML. O sistema de relacionamentos entre documentos está bem descrito no rascunho da especificação e não é o assunto deste artigo.
O esquema geral é visível na imagem:

.
Para implementar importações, um novo tipo foi adicionado aos tipos de links HTML (valores do atributo rel).
A palavra de importação especificada no valor do atributo rel do próprio elemento <link> cria um link para o recurso importado (o tipo padrão do recurso é text / html).
O elemento <link> pode ter um atributo assíncrono.
As extensões oferecidas pelas especificações de rascunho são oferecidas na API HTMLLinkElement: uma propriedade de importação somente leitura é adicionada que contém o documento importado.
Uma propriedade pode conter nulo em dois casos: quando <link> não representa importação ou <link> não está no documento.
A especificação afirma separadamente que o mesmo objeto deve sempre ser retornado.
No contexto das importações, existe o chamado documento mestre, que é o documento que importa recursos ao mesmo tempo sem ser o recurso importado de outra pessoa.
O ContentSecurityPolicy desse documento deve limitar todas as importações. Portanto, se o Campo de cabeçalho de segurança de conteúdo estiver definido para importação, o navegador deverá aplicar a política do documento mestre ao documento importado.
Na prática
Para o componente da guia, eu crio uma pasta de modelos. Nele, criarei dois arquivos nos quais transferirei a marcação do 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>
No <head> do arquivo index.html, importo os modelos:
<link rel="import" href="templates/tab-nav.html" id="tab-nav"> <link rel="import" href="templates/tab-content.html" id="tab-content">
Eu adiciono atributos de identificação aos elementos <link>, pois precisarei acessá-los a partir de js.
Agora, nos construtores das classes TabNavigationItem e TabContentItem, para obter o documento do modelo, só preciso encontrar o elemento <link> correspondente e retornar à sua propriedade import, após o que procurarei o modelo já existente no 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'); }
A versão final pode ser obtida aqui .
Sobre o Suporte
Suporte para modelos HTML: Edge c 16, Firefox c 59, Chrome c 49, Safari c 11.
Com o suporte à importação mais antigo: Chrome c 49.
Portanto, os exemplos deste artigo podem ser vistos apenas no Chrome mais recente.
Existem polifilos:
Componentes da WebProjeto de polímeroLeia mais sobre modelos e importações:
Especificação HTMLEspecificação HTML5HTML importa especificações de rascunhoIsso é tudo, obrigado por assistir,
Tanya