Шаблонные ссылки: ref на элемент

Иногда нужен прямой доступ к настоящему DOM-элементу — фокус на поле, измерение размеров, работа с canvas. Разбираем механизм шаблонных ссылок.

Template ref (шаблонная ссылка) — способ получить ссылку на реальный DOM-элемент из кода компонента, не прибегая к document.querySelector.

Когда это нужно

Vue сам управляет DOM, и руками туда лезть обычно не надо. Но есть исключения: поставить фокус в поле ввода, прокрутить к элементу, измерить его ширину, отдать canvas сторонней библиотеке графиков. Для этого и нужны template refs.

Как устроена шаблонная ссылка

Механизм из двух частей: атрибут ref="имя" на элементе в шаблоне и одноимённая ref-переменная в скрипте. Vue свяжет их, когда элемент окажется в DOM:

<template>
  <input ref="inputEl" placeholder="Я получу фокус">
</template>

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

const inputEl = ref(null)   // имя совпадает с ref в шаблоне

onMounted(() => {
  inputEl.value.focus()     // ставим фокус в поле
})
</script>

Главное правило: только после монтирования

До монтирования настоящего элемента ещё нет, поэтому inputEl.value равен null. Обращаться к нему можно только в onMounted или позже — например, по клику. Попытка достучаться раньше даст ошибку «cannot read property of null». Промоделируем этот жизненный путь:

// Имитация: элемент появляется только в onMounted
let elementRef = { value: null };

function tryFocus(label) {
  if (elementRef.value === null) {
    console.log(`${label}: элемента ещё нет (null)`);
  } else {
    console.log(`${label}: фокус на «${elementRef.value}»`);
  }
}

tryFocus("До mounted");
elementRef.value = "input#name";   // onMounted: Vue связал ссылку
tryFocus("После mounted");

Вывод:

До mounted: элемента ещё нет (null)
После mounted: фокус на «input#name»

Не злоупотребляйте

Template refs — «аварийный люк» в императивный мир. Если вы тянетесь к нему, чтобы поменять текст или видимость элемента — остановитесь: это задача реактивности ({{ }}, v-if). Шаблонные ссылки нужны только для того, что декларативно не выразить: фокус, прокрутка, измерения, интеграция со сторонним кодом.

ЗадачаПравильный инструмент
Поменять текст элементаинтерполяция {{ }}
Показать/скрытьv-if / v-show
Поставить фокус, измерить, прокрутитьtemplate ref

Итог

  • Template ref даёт прямой доступ к DOM-элементу без querySelector.
  • Атрибут ref="имя" в шаблоне + одноимённая ref-переменная в скрипте.
  • Элемент доступен только начиная с onMounted; раньше .value равен null.
  • Используйте лишь для фокуса, измерений, прокрутки и интеграций — не для текста и видимости.
Проверьте себя
1. Как связать переменную скрипта с DOM-элементом через template ref?
AЧерез document.getElementById внутри setup
BПоставить ref="имя" на элемент в шаблоне и создать одноимённую ref-переменную в скрипте
CЧерез :element="имя"
DЧерез provide/inject
2. Когда становится доступен реальный DOM-элемент через template ref?
AСразу в начале <script setup>
BТолько начиная с onMounted; до этого .value равен null
CТолько в onUnmounted
DВ любой момент, ещё до рендера
3. Для какой задачи template ref НЕ подходит?
AПоставить фокус в поле
BИзмерить ширину элемента
CПоменять текст элемента — для этого есть реактивность и {{ }}
DПрокрутить страницу к элементу
Поддержать проект