Componentes da Web Parte 3: modelos e importações de html

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 personalizados
Componentes da Web Parte 2: sombra DOM

Este 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.


  <!--templates/tab-content.html--> <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> <!--templates/tab-nav.html--> <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'); } //... } class TabContentItem extends HTMLElement { constructor() { super(); this._target = null; this.attachShadow({mode: 'open'}); const templateImport = document.getElementById('tab-content').import; this.template = templateImport.getElementById('tab-content'); } //... } 

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 Web
Projeto de polímero

Leia mais sobre modelos e importações:

Especificação HTML
Especificação HTML5
HTML importa especificações de rascunho

Isso é tudo, obrigado por assistir,
Tanya

Source: https://habr.com/ru/post/pt414905/


All Articles