Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Ссылки на элементы шаблона

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

Фокус в поле ввода

<!-- src/components/TodoForm.vue -->
<script setup>
import { onMounted, useTemplateRef } from 'vue'
 
const input = useTemplateRef('todo-input')
 
onMounted(() => {
  input.value.focus()
})
</script>
 
<template>
  <input ref="todo-input" placeholder="Что нужно сделать?">
</template>

Подключите TodoForm в App.vue и откройте страницу — курсор сразу окажется в поле, можно печатать без клика. useTemplateRef появилась в Vue 3.5: она принимает значение атрибута ref и возвращает объект, в .value которого лежит элемент DOM.

Когда ссылка заполнена

До монтирования элемента ещё нет, поэтому input.value равно null. Обращайтесь к нему в onMounted или в обработчиках событий:

<!-- src/components/TodoForm.vue -->
<script setup>
import { ref, useTemplateRef } from 'vue'
 
const emit = defineEmits(['add'])
const text = ref('')
const input = useTemplateRef('todo-input')
 
function submit() {
  if (text.value.trim() === '') return
  emit('add', text.value.trim())
  text.value = ''
  input.value.focus()
}
</script>
 
<template>
  <form @submit.prevent="submit">
    <input ref="todo-input" v-model="text" placeholder="Что нужно сделать?">
    <button>Добавить</button>
  </form>
</template>

После нажатия на кнопку «Добавить» фокус возвращается в поле, и можно сразу вводить следующую задачу.

Старая запись

До Vue 3.5 ссылку объявляли через обычный ref с тем же именем, что и атрибут:

<script setup>
import { ref, onMounted } from 'vue'
 
const todoInput = ref(null)
 
onMounted(() => todoInput.value.focus())
</script>
 
<template>
  <input ref="todoInput">
</template>

Этот вариант работает и сейчас, и вы будете встречать его в чужом коде.

Ссылка на компонент

Атрибут ref можно поставить и на дочерний компонент. С <script setup> компонент по умолчанию закрыт: снаружи видно только то, что он открыл макросом defineExpose:

<!-- src/components/TodoForm.vue -->
<script setup>
// ...код из примера выше
 
function focus() {
  input.value.focus()
}
 
defineExpose({ focus })
</script>

Теперь родитель, получив ссылку через useTemplateRef('form') на <TodoForm ref="form" />, может вызвать form.value.focus().

Частая ошибка

Обратиться к ссылке в коде верхнего уровня <script setup>:

<script setup>
import { useTemplateRef } from 'vue'
 
const input = useTemplateRef('todo-input')
input.value.focus() // TypeError: Cannot read properties of null
</script>

Код выполняется до появления элементов на странице. Переносите такие вызовы в onMounted. Если элемент выводится через v-if, проверяйте ссылку перед использованием: input.value?.focus().

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.