Vue.js: Refs e DOM

Última atualização: 2026-10-20

As referências de modelo permitem que você acesse diretamente elementos do DOM ou instâncias de componentes filhos — por exemplo, chamando input.focus() ou acessando métodos de componentes. O Vue 3.5 introduziu a API de Composição useTemplateRef, mais poderosa, que funciona em conjunto com a inferência de tipos do TypeScript.

Os Template Refs são um “último recurso” — o Vue recomenda o uso de refs, reactive, props e emit para resolver a maioria dos problemas; os Template Refs só devem ser usados quando você precisar manipular diretamente o DOM ou uma instância de componente.

Diretivas relacionados:v-for v-if

1. O que você vai aprender


2. O dilema do “foco automático” em um formulário de login

(1) Problema: Como fazer com que o campo de entrada receba o foco automaticamente quando a janela modal for aberta?

Alice criou um modal de login que deveria colocar o foco automaticamente no campo de nome de usuário:

JS
// ❌ The "Broken" Version:Directly querySelector
onMounted(() => {
  const input = document.querySelector('.username-input')
  input.focus()  // ❌ Does not meet the requirements Vue Philosophy
})

A filosofia do Vue: evite a manipulação direta do DOM. Em vez disso, use Template Refs.

O gerente de produto Charlie:

“Alice, quando a janela modal abrir, o campo do nome de usuário deve receber o foco automaticamente para que os usuários possam começar a digitar imediatamente.”

(2) Solução para referências de modelos de visualização

(3) Receita

Após usar as referências de modelo:


3. Uso básico do ref

(1) Referência de string (estilo Vue 2, obsoleta)

JS
// ❌ Not recommended:String ref
export default {
  mounted() {
    this.$refs.input.focus()
  }
}

(2) A variável ref (recomendada no Vue 3)

(3) 5 Operações básicas

JS
// 1. Visit DOM Element
inputRef.value  // <input> Element

// 2. Call DOM API
inputRef.value.focus()
inputRef.value.blur()
inputRef.value.select()
inputRef.value.scrollIntoView()

// 3. Read/Edit DOM Properties
inputRef.value.value  // input value
inputRef.value.disabled  // disabled Properties
inputRef.value.style.color = 'red'  // Edit Style

// 4. Monitoring DOM Events (Not recommended, use @event)
inputRef.value.addEventListener('focus', handler)

// 5. Accessing a Child Component Instance(For more details, see 17.4)
childRef.value.someMethod()

▶ Exemplo: Foco automático no formulário de login

▶ Experimente

Saída:

TEXT
Ao abrir a tela, o campo Usuário já está com o cursor (focus no onMounted).
Preencher alice / senha123 e enviar → console: Login: alice senha123.
Se o ref não existir no template, usernameRef.value seria null e o focus quebraria.

▶ Exemplo: Rolagem automática até o final da página

▶ Experimente

Saída:

TEXT
Chat vazio na primeira renderização.
Enviar "Oi" → a mensagem entra na lista, o campo é limpo e a caixa rola até ela.
Sem o await nextTick() a rolagem aconteceria antes do DOM receber o novo item.

4. useTemplateRef (Recomendado para Vue 3.5+)

(1) Por que o useTemplateRef é necessário?

A variável ref em <script setup> requer dois nomes (o modelo ref e a variável), o que pode facilmente levar a inconsistências. useTemplateRef lida com isso usando um único nome, e a inferência de tipos do TypeScript é mais poderosa.

(2) 5 principais vantagens

Vantagem Descrição
Inferência de tipo O TypeScript reconhece automaticamente como um HTMLInputElement
Renomeação segura Altere um nome em um único lugar; o IDE sincroniza a alteração
Como evitar incompatibilidades de nomes Ocorrem erros quando as referências de modelo e os nomes das variáveis não coincidem
Configuração simplificada Não é necessário o const inputRef = ref(null)
DevTools aprimoradas Suporte ao Vue DevTools 5.x

(3) Comparação completa

VUE
<!-- Old notation:Variable ref -->
<template>
  <input ref="usernameInput">
</template>

<script setup>
import { ref, onMounted } from 'vue'
const inputRef = ref(null)  // The name may not match the template.
onMounted(() => inputRef.value.focus())
</script>

<!-- New Writing Style:useTemplateRef(Vue 3.5+ Recommendations)-->
<template>
  <input ref="usernameInput">
</template>

<script setup>
import { useTemplateRef, onMounted } from 'vue'
const inputRef = useTemplateRef('usernameInput')  // One Name Does It All
onMounted(() => inputRef.value.focus())
</script>

5. Acessando uma instância de um componente filho

(1) defineExpose: Método Expose

(2) Acesso ao componente pai

VUE
<template>
  <MyInput ref="myInputRef" v-model="searchQuery" />
  <button @click="focusInput">Focus Input</button>
</template>

<script setup>
import { ref } from 'vue'
import MyInput from './MyInput.vue'

const searchQuery = ref('')
const myInputRef = ref(null)

function focusInput() {
  myInputRef.value.focus()  // Calling Methods Exposed by Child Components
  myInputRef.value.select() // You can also use chained calls
}
</script>

(3) 5 principais casos de uso

Cenário Exposto pelo componente filho Chamado pelo componente pai
Destaque do formulário focus() inputRef.focus()
Limpar formulário clear() formRef.clear()
Atualizar dados reload() tableRef.reload()
Abrir janela pop-up open() modalRef.open()
Enviar formulário submit() formRef.submit()

▶ Exemplo: Componente pai chamando um método de um componente filho

VUE
<!-- Child component:FormValidator.vue -->
<template>
  <form>
    <input v-model="email" placeholder="Email">
    <input v-model="password" type="password" placeholder="Password">
  </form>
</template>

<script setup>
import { ref } from 'vue'

const email = ref('')
const password = ref('')

const emailRef = ref(null)
const passwordRef = ref(null)

defineExpose({
  validate: () => {
    if (!email.value) {
      emailRef.value.focus()
      return false
    }
    if (!password.value || password.value.length < 6) {
      passwordRef.value.focus()
      return false
    }
    return true
  },
  reset: () => {
    email.value = ''
    password.value = ''
  }
})
</script>

<!-- Parent Component:LoginPage.vue -->
<template>
  <FormValidator ref="formRef" />
  <button @click="submit">Submit</button>
</template>

<script setup>
import { ref } from 'vue'
import FormValidator from './FormValidator.vue'

const formRef = ref(null)

function submit() {
  if (formRef.value.validate()) {
    console.log('Valid!')
  } else {
    console.log('Invalid!')
  }
}
</script>
▶ Experimente

Saída:

TEXT
Clicar em Submit com os campos vazios: o foco vai para Email e o console mostra Invalid!.
Preencher email e senha (6+ caracteres) → console: Valid!.
reset() via defineExpose limpa os dois campos do filho.

6. A matriz ref em v-for

(1) Uso básico

(2) Referência dinâmica (v-for com contagem dinâmica)

(3) 5 pontos importantes a serem lembrados

Pontos a serem observados Descrição
Ordem da matriz Corresponde à ordem dos dados no v-for
Reativo Alterações na matriz ref exigem um observador
Renderização condicional as referências podem não ser atualizadas após o v-if
Número de variáveis dinâmicas Uso de referência a objeto ou função
Desempenho Um grande número de referências (mais de 100) pode tornar a renderização mais lenta

7. Exercício abrangente: tipagem de useTemplateRef no TypeScript

▶ Exemplo: Inferência de tipo para useTemplateRef

VUE
<template>
  <input ref="usernameInput" type="text">
  <MyChart ref="chartComponent" :data="chartData" />
</template>

<script setup lang="ts">
import { ref, useTemplateRef, onMounted } from 'vue'
import MyChart from './MyChart.vue'

// ✅ TypeScript Inference:HTMLInputElement | null
const usernameInput = useTemplateRef<HTMLInputElement>('usernameInput')

// ✅ TypeScript Inference:InstanceType<typeof MyChart> | null
const chartComponent = useTemplateRef<InstanceType<typeof MyChart>>('chartComponent')

onMounted(() => {
  // usernameInput.value Automatic is HTMLInputElement
  usernameInput.value?.focus()
  
  // chartComponent.value "Auto" is a component instance
  chartComponent.value?.refresh()
})
</script>
▶ Experimente

Saída:

TEXT
Ao montar, o input recebe o foco e o gráfico executa refresh().
O TypeScript infere HTMLInputElement para o input e a instância de MyChart para o gráfico.
O encadeamento opcional evita erro quando a referência ainda não foi montada.

(1) 📊 5. Referência rápida para 5 erros comuns

Erro Sintoma Solução
Erro ortográfico na referência do modelo o valor da referência é nulo Verifique se os nomes das referências correspondem
Acesso no nível superior setup ref.value é nulo Use onMounted
Acesso dentro de uma janela pop-up Não funciona Use nextTick ou métodos DOM semelhantes
Acesso à matriz de referência no v-for Desalinhamento de índices Use :key para preservar a ordem
Referência entre componentes indefinido Os componentes filhos usam defineExpose

(2) 📊 6. Comparação dos 5 principais tipos de referência

Tipo Exemplo Aplicável a
Elemento DOM ref="inputRef" → HTMLInputElement Acessar input/div
Instância do componente ref="childRef" → Instância do componente Métodos do componente de tom
v-for array ref="itemRefs" → Array Acessando itens da lista
Referência funcional :ref="el => ..." → Elemento único Contagem dinâmica
Referência de string ref="name" → this.$refs Estilo da Visualização 2 (não recomendado)

Diretivas relacionados:v-for v-if

❓ Perguntas Frequentes

P Quando se deve usar Template Refs?
R Em quatro situações: (1) manipulação do DOM (foco/rolagem/canvas); (2) chamada de métodos de componentes; (3) integração de bibliotecas de terceiros (ECharts/Mapbox); (4) medição das dimensões dos elementos. Em outros cenários, use refs, reactive ou props.
P O useTemplateRef é obrigatório no Vue 3.5+?
R Sim. Ele só é compatível com o Vue 3.5+. No Vue 3.4 e versões anteriores, use a variável ref. É preferível usar a inferência de tipos do TypeScript.
P Qual é a diferença entre Template Refs e useRef (React)?
R O useRef do React retorna uma ref mutável, enquanto a template ref do Vue retorna um objeto ref. O useTemplateRef do Vue 3.5+ possui uma API mais próxima da do useRef do React.
P Quais métodos um componente filho deve expor?
R Exponha apenas os métodos de que o componente pai realmente precisa (como focus, clear e validate). Não exponha outros métodos internos (princípio da encapsulação).
P Quando a matriz ref em v-for é atualizada?
R Ela é atualizada sempre que v-for é renderizada novamente. Também é atualizada quando v-if é ativada ou desativada. Você pode usar watch na matriz ref para responder às alterações.
P As Template Refs entram em conflito com o provide/inject?
R Não, não entram. As Template Refs são usadas para o “acesso de pai para filho”, enquanto o provide/inject é usado para o “compartilhamento de dados entre níveis”. Elas podem ser usadas em conjunto.
P Como faço para adicionar um tipo a uma referência no TypeScript?
R Use useTemplateRef<HTMLInputElement>('usernameInput'). Ou ref<HTMLInputElement | null>(null).

📖 Resumo


📝 Exercícios

  1. Questões básicas (Dificuldade: ⭐)

    Implemente um formulário simples de foco automático:

    • 1 campo de entrada + 1 botão
    • O campo de entrada recebe o foco automaticamente após o carregamento da página
    • Quando o botão é clicado, o texto do botão muda para “Enviado” e o botão fica desativado
  2. Problemas avançados (Dificuldade: ⭐⭐)

    Implementar uma janela de bate-papo que role automaticamente até o final da página:

    • Lista de mensagens (contêiner div)
    • Campo de entrada + botão “Enviar”
    • Depois que uma mensagem é enviada, ela é adicionada à lista e a tela rola automaticamente até o final
    • Use v-for para renderizar mensagens e uma matriz ref para gerenciar o DOM
  3. Problema desafiador (Dificuldade: ⭐⭐⭐)

    Implementar um sistema completo de “componentes pai-filho + Template Refs”:

    1. Subcomponente FormValidator: disponibiliza os métodos validate() e reset()
    2. Componente pai da LoginPage: chama o método validate para realizar a validação; exibe uma mensagem de erro caso a validação falhe
    3. 5 campos de preenchimento (nome de usuário/e-mail/senha/telefone/captcha)
    4. useTemplateRef (Vue 3.5+) + tipagem forte do TypeScript
    5. Colocar o foco automaticamente no primeiro campo de entrada quando a janela pop-up for aberta
    6. Quando ocorrer um erro, concentre-se no primeiro campo de erro
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%