APIs HTML

Na introdução desta série, diz que "os elementos HTML são os nós que formam o modelo de objeto do documento". Discutimos o tipo de nós de elementos. Nesta seção, abordamos as APIs de elementos que permitem consultar esses nós.

DOM e AOM

O DOM é uma API para acessar e manipular documentos. O DOM é a árvore de todos os nós do documento. Alguns nós podem ter filhos, outros não. A árvore inclui elementos, atributos e nós de texto.

Árvore de nós MLW mostrando elementos e nós de texto.

As ferramentas do navegador não oferecem visualizações de árvore como a mostrada acima, mas você pode conferir os nós no elemento inspector.

O DOM/ARIA.

A representação em árvore que pode ser inspecionada nas ferramentas para desenvolvedores do navegador é a árvore de acessibilidade. O AOM é baseado no DOM. Da mesma forma, a árvore de acessibilidade contém objetos que representam todos os elementos de marcação, atributos e nós de texto:

Exemplo de AOM.

APIs de elemento HTML

A letra do meio do DOM é "object". Assim como o exemplo de objeto person ou car da maioria das aulas introdutórias de programação orientada a objetos, cada nó na árvore de documentos é um objeto que pode ser manipulado com JavaScript.

O navegador oferece várias APIs que fornecem métodos, eventos e consultas e atualizações de propriedade com suporte nativo. Os nós de elemento contêm informações sobre todos os atributos definidos no elemento. É possível usar interfaces HTML para acessar informações sobre os atributos de um elemento. Por exemplo, podemos usar HTMLImageElement.alt para receber os atributos alt de todas as imagens:

let allImages = document.querySelectorAll('img');
allImages.forEach((imageInstance) => {
  console.log(imageInstance.alt);
});

As interfaces HTML oferecem mais do que apenas acesso aos atributos de um elemento. Você pode acessar muito mais informações. Podemos encontrar o HTMLElement.offsetHeight somente leitura para saber a altura de cada seção na página em relação ao layout.

let allSections = document.querySelectorAll('section');
allSections.forEach((sectionInstance) => {
  console.log(sectionInstance.offsetHeight);
});

Se o usuário mudar a orientação do dispositivo ou a largura da janela de visualização, a altura de cada <section> vai mudar e as propriedades do DOM serão atualizadas automaticamente.

As APIs da interface HTML não se limitam a acessar valores de atributos. O DOM fornece insights sobre o estado atual da interface. As APIs HTML podem acessar todas essas informações. É possível acessar a duração de um vídeo, onde uma visualização está na reprodução atual e se o vídeo (ou áudio) terminou de ser reproduzido com HTMLMediaElement.duration, HTMLMediaElement.currentTime e HTMLMediaElement.ended, respectivamente.

Interfaces de elementos disponíveis

A maioria dos elementos HTML que abordamos até agora nesta série e que ainda vamos abordar, exceto alguns elementos de seção, têm uma interface DOM associada. A interface de base para todos os elementos é apropriadamente chamada de Elemento. O HTMLElement herda do elemento, e todas as interfaces específicas de elementos HTML herdam dele. Algumas interfaces específicas de elementos são implementadas por vários elementos semelhantes.

As interfaces incluem:

A convenção de nomenclatura é "HTML" seguida por um elemento ou grupo de elementos em maiúsculas, seguida por "Elemento", mas a parte do elemento ou grupo de elementos não segue um padrão exato. Não se preocupe. Não é necessário memorizá-los. É importante saber que eles existem para que você possa consultá-los quando precisar.

Se você tiver uma coleção de elementos, também haverá interfaces de coleção. Por exemplo, o método HTMLCollection.namedItem() retorna o primeiro elemento na coleção cujo atributo id ou name corresponde ao parâmetro ou nulo se nenhum elemento corresponder.

Mais de 30 elementos não têm uma interface DOM associada, exceto HTMLElement, incluindo <address>, <article>, <section>, <nav>, <header>, <footer>, <aside> e <hgroup>. Muitos elementos que não oferecem suporte a atributos não descontinuados e não globais têm interfaces específicas do elemento, como HTMLPElement (o elemento <p>) e HTMLUnknownElement (<😃> ou qualquer outro elemento que não esteja definido), mas essas interfaces não implementam propriedades ou métodos adicionais além das propriedades e métodos herdados de HTMLElement e não estão listados acima.

Métodos e propriedades redundantes da API

Se uma interface tiver o mesmo nome de método ou propriedade que uma interface que ela herda, o método ou a propriedade que herda vai substituir a herdada. Em outras palavras, os métodos e propriedades mães substituem os filhos. Quando acessamos as propriedades alt e offsetHeight nas APIs de elementos HTML com imageInstance.alt e sectionInstance.offsetHeight, respectivamente, o código não identificava qual API estava sendo acessada. Geralmente, como nestes dois exemplos, isso não é um problema.

No entanto, há alguns casos em que a redundância pode causar problemas. Por exemplo, HTMLCollection.length é somente leitura, enquanto a interface herdada, HTMLOptionsCollection, tem uma propriedade de comprimento (retornada apenas pela propriedade options de <select>) com acesso de leitura e gravação. HTMLOptionsCollection pode ser usado para definir o tamanho da coleta.

Outras interfaces

Há outras interfaces que permitem manipular os locais de ramificação dos nós do DOM. A interface EventTarget, que fornece addEventListener() e removeEventListener(), é herdada pelas interfaces Node e Window. Por sua vez, as interfaces Element, Document e DocumentFragment (que vimos em elementos personalizados) herdam de Node, e a interface HTMLElement herda de Element.

Interface node

Cada tipo de nó DOM é representado por uma interface baseada em Node, que fornece informações e métodos, já que os elementos se relacionam à árvore DOM. A interface Node permite consultar e adicionar nós à árvore de nós.

A famosa função "walk the DOM" de Douglas Crockford usa as propriedades firstChild e nextSibling do Node.

const walk_the_DOM = function walk(node, callback) {
  callback(node);
  node = node.firstChild;
  while (node) {
    walk(node, callback);
    node = node.nextSibling;
  }
};

Usamos os métodos appendChild() e cloneNode() do Node para definir elementos personalizados. A interface do nó fornece muitas propriedades e métodos úteis para consultar e manipular o DOM.

customElements.define('star-rating',
  class extends HTMLElement {
    constructor() {
      super(); // Always call super first in constructor
      const starRating = document.getElementById('star-rating-template').content;
      const shadowRoot = this.attachShadow({
        mode: 'open'
      });
      shadowRoot.appendChild(starRating.cloneNode(true));
    }
  });

O método attachShadow() é um método da interface Element. Há também uma interface shadowRoot para a API Shadow DOM renderizada separadamente da árvore principal do DOM de um documento.