Template refs и nextTick

↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Доступ к DOM и «почему DOM ещё не обновился» — типичные вопросы.

Объяснение

Template ref — ссылка на DOM-элемент или экземпляр компонента.

<script setup lang="ts">
import { ref, useTemplateRef, onMounted, nextTick } from "vue";
 
const input = useTemplateRef<HTMLInputElement>("nameInput");      // 3.5+ (или ref<HTMLInputElement | null>(null) с тем же именем)
const list = ref<HTMLElement | null>(null);
const rows = useTemplateRef<HTMLElement[]>("rows");                // в v-for — массив
 
onMounted(() => input.value?.focus());
 
async function add() {
  items.value.push(newItem());
  await nextTick();                                                // ждём обновления DOM
  list.value?.lastElementChild?.scrollIntoView();
}
</script>
 
<template>
  <input ref="nameInput" />
  <ul ref="list"><li v-for="i in items" :key="i.id" ref="rows">{{ i.title }}</li></ul>
  <ChildForm ref="form" />                                         <!-- экземпляр компонента: доступен только defineExpose -->
</template>

nextTick: Vue применяет изменения DOM асинхронно и пакетно (одна отрисовка за тик). После изменения состояния DOM ещё не обновлён; await nextTick() (или nextTick(cb)) выполняется после обновления.

count.value++;
console.log(el.value.textContent);      // старое
await nextTick();
console.log(el.value.textContent);      // новое

Функции-ref: :ref="(el) => setRef(el, id)" — для динамических случаев.

Использования: фокус, измерение размеров, прокрутка, инициализация библиотек с DOM, вызов методов дочернего компонента (form.value?.validate()).

Нюансы и подводные камни

  • Ref пуст (null) до монтирования и при v-if false.
  • Порядок элементов в массиве refs в v-for не гарантирован.
  • Для доступа к дочернему компоненту нужен defineExpose.
  • Злоупотребление refs вместо данных/событий делает код императивным.
  • Изменение состояния и чтение DOM в одном тике даёт устаревшие значения.

Практика

  1. Фокусируйте поле после появления через nextTick.
  2. Прокрутите список к добавленному элементу.
  3. Вызовите validate() дочерней формы через ref.

Вопросы с ответами

Связанные темы