Bem-vindo à aula sobre Web APIs úteis do navegador. Nesta aula, vamos explorar cinco APIs fundamentais que todo desenvolvedor JavaScript deve dominar para criar aplicações web ricas e interativas. Essas APIs fornecem acesso a informações do navegador e do sistema, permitindo que você personalize a experiência do usuário, gerencie a navegação, responda a mudanças no ambiente e integre funcionalidades como copiar e colar.

Entender essas APIs é crucial para construir aplicações modernas que se adaptam a diferentes dispositivos e contextos. Vamos mergulhar em cada uma delas, com exemplos práticos e boas práticas, para que você possa aplicá-las imediatamente em seus projetos.

navigator

A API navigator fornece informações sobre o navegador e o sistema operacional do usuário. É um objeto global que contém propriedades e métodos úteis para detectar recursos, obter dados de geolocalização, verificar o estado da conexão e muito mais.

Algumas propriedades comuns incluem navigator.userAgent (identificação do navegador), navigator.language (idioma preferido do usuário), navigator.onLine (estado da conexão) e navigator.platform (plataforma do sistema). Além disso, métodos como navigator.geolocation.getCurrentPosition() permitem obter a localização do usuário, e navigator.clipboard (que veremos mais adiante) oferece acesso à área de transferência.

// Exemplo de uso do navigator
console.log('User Agent:', navigator.userAgent);
console.log('Idioma:', navigator.language);
console.log('Online?', navigator.onLine);

// Verificar se a geolocalização está disponível
if ('geolocation' in navigator) {
  navigator.geolocation.getCurrentPosition(position => {
    console.log('Latitude:', position.coords.latitude);
    console.log('Longitude:', position.coords.longitude);
  });
} else {
  console.log('Geolocalização não suportada.');
}

É importante usar a detecção de recursos para evitar erros em navegadores que não suportam determinadas APIs. Por exemplo, sempre verifique se navigator.geolocation existe antes de chamar seus métodos. Além disso, lembre-se de que a geolocalização requer permissão do usuário.

location

O objeto location representa a URL atual do documento e permite que você a manipule. Ele contém propriedades como href, protocol, host, pathname, search (query string) e hash. Com ele, você pode redirecionar o usuário, recarregar a página ou modificar partes da URL.

Um uso comum é redirecionar para outra página com location.href = 'https://exemplo.com' ou location.assign('url'). Também é possível recarregar a página com location.reload() e obter parâmetros da URL via URLSearchParams.

// Exemplo de uso do location
console.log('URL completa:', location.href);
console.log('Protocolo:', location.protocol);
console.log('Host:', location.host);
console.log('Caminho:', location.pathname);
console.log('Query:', location.search);

// Redirecionar para outra página
// location.href = 'https://www.exemplo.com';

// Obter parâmetros da URL
const params = new URLSearchParams(location.search);
const id = params.get('id');
console.log('ID da URL:', id);

Tenha cuidado ao redirecionar ou recarregar a página, pois isso pode interromper a execução do script. Prefira usar location.assign() para navegação e location.replace() se não quiser manter a página atual no histórico.

history

A API history permite que você interaja com o histórico de navegação do navegador, ou seja, as páginas que o usuário visitou. Ela oferece métodos como back(), forward() e go() para navegar pelo histórico. Além disso, você pode manipular o histórico sem recarregar a página usando pushState() e replaceState(), que são essenciais para aplicações de página única (SPA).

Com history.pushState(), você pode adicionar uma nova entrada ao histórico e alterar a URL sem recarregar a página. Isso é útil para criar navegação dinâmica. O evento popstate é disparado quando o usuário navega pelo histórico (por exemplo, clicando nos botões voltar/avançar).

// Exemplo de uso do history
// Navegar para trás
history.back();

// Navegar para frente
history.forward();

// Ir para uma posição específica (-1 = voltar, 1 = avançar)
history.go(-2);

// Manipular o histórico sem recarregar
const state = { page: 'sobre' };
history.pushState(state, '', '/sobre');

// Ouvir o evento popstate
window.addEventListener('popstate', event => {
  console.log('Estado:', event.state);
  console.log('URL atual:', location.href);
});

O uso de pushState é fundamental para criar SPAs com navegação fluida. Lembre-se de que o evento popstate não é disparado quando você chama pushState() diretamente, apenas quando o usuário navega pelo histórico.

matchMedia

A API matchMedia permite que você avalie media queries CSS em JavaScript e reaja a mudanças no ambiente de exibição, como largura da janela, orientação, resolução e preferências do usuário (ex.: modo escuro). Ela retorna um objeto MediaQueryList que pode ser usado para verificar se a media query é verdadeira e para ouvir mudanças.

Isso é extremamente útil para criar layouts responsivos ou para adaptar o comportamento da aplicação com base no tamanho da tela ou nas preferências do usuário. Por exemplo, você pode carregar recursos diferentes para telas grandes ou pequenas, ou ativar/desativar animações conforme a preferência de reduzir movimento.

// Exemplo de uso do matchMedia
const mediaQuery = window.matchMedia('(max-width: 768px)');

// Verificar se a media query é verdadeira
if (mediaQuery.matches) {
  console.log('Tela pequena (mobile)');
} else {
  console.log('Tela grande (desktop)');
}

// Ouvir mudanças
mediaQuery.addEventListener('change', event => {
  if (event.matches) {
    console.log('Mudou para tela pequena');
  } else {
    console.log('Mudou para tela grande');
  }
});

// Exemplo com preferência de tema escuro
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
console.log('Tema escuro ativo?', darkModeQuery.matches);

Use addEventListener para reagir a mudanças em vez de addListener (que é mais antigo). Sempre remova os listeners quando não precisar mais deles para evitar vazamentos de memória.

clipboard (visão geral)

A API clipboard fornece acesso à área de transferência do sistema, permitindo ler e escrever texto, imagens e outros dados. Ela é assíncrona e baseada em Promises, e geralmente requer permissão do usuário. As principais operações são navigator.clipboard.writeText() e navigator.clipboard.readText().

Devido a questões de segurança, o acesso à área de transferência só é permitido em contextos seguros (HTTPS) e após a interação do usuário (por exemplo, um clique). Além disso, é necessário solicitar permissão usando a Permissions API.

// Copiar texto para a área de transferência
async function copiarTexto(texto) {
  try {
    await navigator.clipboard.writeText(texto);
    console.log('Texto copiado!');
  } catch (err) {
    console.error('Falha ao copiar:', err);
  }
}

// Ler texto da área de transferência
async function lerTexto() {
  try {
    const texto = await navigator.clipboard.readText();
    console.log('Texto lido:', texto);
  } catch (err) {
    console.error('Falha ao ler:', err);
  }
}

// Exemplo de uso
// copiarTexto('Olá, mundo!');
// lerTexto();

Lembre-se de que a leitura da área de transferência pode exibir um prompt de permissão para o usuário. Sempre trate erros, pois a operação pode falhar se a permissão for negada ou se o contexto não for seguro.

Boas práticas e observações finais

Ao trabalhar com essas APIs, sempre verifique a compatibilidade com o navegador e use a detecção de recursos. Para navigator, location e history, não há grandes problemas de compatibilidade, mas para matchMedia e clipboard, é importante testar em diferentes navegadores.

Além disso, lembre-se de que a API clipboard requer um contexto seguro (HTTPS) e permissão explícita. Para aplicações que precisam de suporte a navegadores mais antigos, considere fallbacks como document.execCommand('copy') (embora seja obsoleto).

Por fim, use essas APIs para melhorar a experiência do usuário, mas sempre com responsabilidade, respeitando a privacidade e as permissões.

Referências

Exercícios

  1. Exercício 1: Escreva uma função que usa navigator para verificar se o navegador está online e se a geolocalização está disponível. Se estiver, exiba a latitude e longitude no console.
  2. ✓ Resposta:
    function verificarNavegador() {
      console.log('Online?', navigator.onLine);
      if ('geolocation' in navigator) {
        navigator.geolocation.getCurrentPosition(pos => {
          console.log('Latitude:', pos.coords.latitude);
          console.log('Longitude:', pos.coords.longitude);
        }, err => console.error('Erro:', err.message));
      } else {
        console.log('Geolocalização não suportada.');
      }
    }
    verificarNavegador();
    
  3. Exercício 2: Crie uma função que redirecione o usuário para a página inicial do site (ex.: '/') usando location, mas sem recarregar a página se já estiver nela.
  4. ✓ Resposta:
    function irParaHome() {
      if (location.pathname !== '/') {
        location.href = '/';
      } else {
        console.log('Já está na home.');
      }
    }
    irParaHome();
    
  5. Exercício 3: Implemente um botão que, ao ser clicado, adiciona um novo estado ao histórico usando history.pushState() e muda o texto do título da página para 'Página 2'.
  6. ✓ Resposta:
    document.getElementById('meuBotao').addEventListener('click', () => {
      history.pushState({ page: 'pagina2' }, '', '/pagina2');
      document.title = 'Página 2';
    });
    
  7. Exercício 4: Use matchMedia para detectar se o dispositivo está em modo paisagem (orientation: landscape) e exiba uma mensagem no console quando a orientação mudar.
  8. ✓ Resposta:
    const paisagem = window.matchMedia('(orientation: landscape)');
    function verificarOrientacao(e) {
      if (e.matches) {
        console.log('Modo paisagem');
      } else {
        console.log('Modo retrato');
      }
    }
    paisagem.addEventListener('change', verificarOrientacao);
    verificarOrientacao(paisagem);
    
  9. Exercício 5: Escreva uma função que copia um texto para a área de transferência usando navigator.clipboard.writeText() e exiba um alerta de sucesso ou erro.
  10. ✓ Resposta:
    async function copiarTexto(texto) {
      try {
        await navigator.clipboard.writeText(texto);
        alert('Texto copiado!');
      } catch (err) {
        alert('Falha ao copiar: ' + err.message);
      }
    }
    // Exemplo de uso: copiarTexto('Olá, mundo!');