W3docs

API de Selection e Range em JavaScript

Aprenda a usar as interfaces Selection e Range do JavaScript para manipular texto selecionado, criar intervalos e construir editores de texto ricos no DOM.

Sempre que um utilizador arrasta o cursor sobre o texto de uma página, o navegador regista o que foi selecionado. O JavaScript expõe essa informação — e permite criar seleções por programação — através de duas interfaces DOM relacionadas:

  • Um Range é um par de pontos de fronteira (um início e um fim) dentro do documento. Descreve qual parte do documento está em causa, até ao desvio de caractere específico dentro de um nó de texto. Um range pode existir apenas em memória sem que o utilizador tenha conhecimento disso.
  • Uma Selection é o que o utilizador tem realçado no momento. É essencialmente um invólucro em torno de um ou mais ranges, associado ao realce na ecrã e ao cursor de texto (caret).

Estas APIs são úteis quando se precisa de construir um editor de texto rico, uma funcionalidade de "realçar e comentar", um localizar-e-substituir personalizado, ou qualquer coisa que leia, mova ou aplique estilos a texto selecionado por programação. Este capítulo aborda a criação de ranges, a leitura e alteração da seleção do utilizador, e a combinação de ambos para realçar e inserir conteúdo.

Este capítulo baseia-se na forma como o DOM é estruturado. Se os tipos de nós e os desvios são novidades para si, leia primeiro Propriedades de nós: tipo, tag e conteúdos e Modificar o documento.

Compreender a Interface Selection

A interface Selection representa o texto que o utilizador realçou, ou a posição atual do caret quando nada está realçado. Acede-se a ela com o método global window.getSelection() (frequentemente apenas getSelection()). Internamente, uma selection contém zero ou mais objetos Range; na prática, a maioria dos navegadores mantém apenas um único range, pelo que getRangeAt(0) é a forma mais comum de o ler.

A forma mais rápida de ver o que está selecionado é toString(), que devolve o texto selecionado como uma string simples:

// After the user highlights something on the page:
const selectedText = window.getSelection().toString();
console.log(selectedText); // whatever the user highlighted

Propriedades e métodos úteis de Selection

  • rangeCount: O número de ranges na selection — 0 quando nada está selecionado. Verifique sempre este valor antes de chamar getRangeAt.
  • toString(): Devolve o texto selecionado como uma string.
  • getRangeAt(index): Devolve o Range no índice indicado (use 0 para a seleção atual).
  • addRange(range): Adiciona um Range à selection, realçando-o no ecrã.
  • removeAllRanges(): Limpa a selection por completo.
  • removeRange(range): Remove um range específico. A maioria dos navegadores mantém apenas um único range, pelo que removeAllRanges() é a escolha prática.
  • collapse(node, offset): Colapsa a selection para um único ponto (um caret vazio) dentro de node.

Um padrão comum é ler a seleção atual, modificá-la e depois escrever uma nova selection — removeAllRanges() seguido de addRange().

Exemplo prático: realçar texto

Para realçar o que o utilizador selecionou, obtém-se o seu range, removem-se os nós selecionados do documento, envolvem-se num <span> com estilo e coloca-se esse span de volta onde o conteúdo estava.

extractContents() remove o conteúdo selecionado do DOM e devolve-o como um fragmento de documento, deixando o range vazio (colapsado) nesse ponto — que é exatamente onde se insere depois o span.

<div id="text">Select some of this text and press the button.</div>
<button onclick="highlightText()">Highlight</button>

<script>
function highlightText() {
  const selection = window.getSelection();
  if (!selection.rangeCount) return false;
  const range = selection.getRangeAt(0);
  const span = document.createElement('span');
  span.style.backgroundColor = 'yellow';
  const fragment = range.extractContents();
  span.appendChild(fragment);
  range.insertNode(span);
}
</script>

Explorar a Interface Range

Um Range marca um fragmento do documento com dois pontos de fronteira — um início e um fim — cada um definido por um e um desvio. O significado do desvio depende do nó:

  • Dentro de um nó de texto, o desvio é um índice de caractere (por exemplo, o desvio 5 situa-se entre o 5.º e o 6.º caractere).
  • Dentro de um nó de elemento, o desvio conta os nós filhos (por exemplo, o desvio 0 fica antes do primeiro filho).

Crie um range vazio com document.createRange() e posicione as suas fronteiras. Pode encontrar os nós a apontar com getElementById / querySelector.

Definir as fronteiras

const p = document.querySelector('p');
const textNode = p.firstChild;        // the text inside <p>

const range = document.createRange();
range.setStart(textNode, 0);          // start at the first character
range.setEnd(textNode, 5);            // end before the 6th character
console.log(range.toString());        // first 5 characters of the paragraph

Dois atalhos cobrem os casos mais comuns para que não seja necessário calcular desvios:

  • selectNode(node) — o range abrange o nó e as suas tags circundantes.
  • selectNodeContents(node) — o range abrange apenas o que está dentro do nó.

Métodos úteis de Range

  • setStart(node, offset) / setEnd(node, offset): Posiciona as fronteiras de início e fim.
  • selectNode(node) / selectNodeContents(node): Define ambas as fronteiras em torno de um nó ou do seu conteúdo.
  • toString(): O texto dentro do range.
  • cloneContents(): Devolve uma cópia do conteúdo do range como fragmento de documento, sem tocar no documento.
  • extractContents(): Move o conteúdo do documento para um fragmento e devolve-o.
  • deleteContents(): Remove o conteúdo do range sem devolver nada.
  • cloneRange(): Devolve uma cópia do próprio objeto range (não do seu conteúdo).
  • insertNode(node): Insere um nó no início do range.
  • surroundContents(node): Envolve o conteúdo do range dentro de node — útil para realçar, mas lança uma exceção se o range cruzar parcialmente um elemento não textual.

Recorde a diferença: cloneContents() copia, extractContents() move para fora e devolve, deleteContents() remove e descarta.

Exemplo prático: extrair texto

Este exemplo lê tudo dentro de um elemento com um range e transforma o texto sem tocar no DOM original:

<div id="content">This is some sample text for extraction.</div>
<button onclick="extractText()">Extract and Manipulate</button>

<script>
function extractText() {
  const range = document.createRange();
  const content = document.getElementById('content');
  range.selectNodeContents(content);
  const extractedText = range.toString();
  const manipulatedText = extractedText.replace('sample', 'example'); // Manipulating text
  alert(manipulatedText);
}
</script>

No exemplo acima, o script substitui a palavra "sample" por "example" no texto extraído antes de o mostrar numa caixa de alerta. Esta é uma manipulação básica, mas demonstra como se pode começar a trabalhar com o texto depois de extraído.

Operações de Texto Avançadas

Para além da manipulação básica de texto, as interfaces Selection e Range permitem operações mais complexas, como a inserção de nós diretamente no documento.

Exemplo: Inserir Texto

Este exemplo usa uma div com contenteditable: o utilizador clica para posicionar o caret e o botão insere 'Hello World' exatamente nesse ponto. Note como deleteContents() remove primeiro qualquer conteúdo selecionado, depois o novo nó de texto é inserido e re-selecionado para que o caret fique após ele.

<div id="editable" contenteditable="true" style="border: 1px solid #ccc; padding: 10px; min-height: 50px;">
  Click here and set the cursor position.
</div>
<button onclick="insertText()">Insert 'Hello World'</button>

<script>
function insertText() {
  const editableDiv = document.getElementById('editable');
  const sel = window.getSelection();
  
  // Check if the selection is within the editable div
  if (!sel.rangeCount || !editableDiv.contains(sel.getRangeAt(0).commonAncestorContainer)) return;
  
  const range = sel.getRangeAt(0);
  range.deleteContents();  // Clears any selected text

  const textNode = document.createTextNode('Hello World');
  range.insertNode(textNode);

  sel.removeAllRanges();   // Clear the previous selection
  sel.addRange(range);     // Re-select the new text node
}
</script>

Resumo

  • Um Range é dois pontos de fronteira (nó + desvio) que descrevem um fragmento do documento; crie um com document.createRange() e posicione-o com setStart/setEnd ou os atalhos selectNode/selectNodeContents.
  • Uma Selection, obtida via window.getSelection(), envolve o realce do utilizador no ecrã. Leia-a com toString() e getRangeAt(0); reescreva-a com removeAllRanges() + addRange().
  • Para conteúdo: cloneContents() copia, extractContents() move para fora, deleteContents() descarta, e insertNode / surroundContents reinserem nós.

Em conjunto, estas interfaces permitem realçar, extrair e inserir conteúdo com precisão — a base dos editores de texto ricos e das ferramentas de anotação.

Continue a aprender: Modificar o documento · Propriedades de nós: tipo, tag e conteúdos · Pesquisa: getElement* e querySelector

Prática

Prática
Quais das seguintes afirmações são verdadeiras em relação às interfaces Range e Selection do JavaScript?
Quais das seguintes afirmações são verdadeiras em relação às interfaces Range e Selection do JavaScript?
Was this page helpful?