> Как получить доступ к DOM элементам через ref в created и mounted хуках во Vue (Vue.js)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: ЛОЦИЯ, Библио-Глобус

Стек: Vue.js

> Пример ответа

Короткий ответ

В created хуке доступ к DOM элементам через ref невозможен, так как шаблон ещё не отрендерен - $el и $refs равны undefined. В mounted хуке DOM уже смонтирован, поэтому this.$refs.refName возвращает нужный элемент. Для работы с DOM в created используйте $nextTick или перенесите логику в mounted.

Подробное объяснение

Во Vue жизненный цикл компонента строго регламентирован. Хук created вызывается сразу после инициализации options (data, computed, methods, watch), но до компиляции шаблона и монтирования в DOM. На этом этапе виртуальный DOM ещё не создан, поэтому this.$refs - пустой объект, а this.$el - undefined. Любая попытка обратиться к this.$refs.myRef вернёт undefined.

Хук mounted вызывается после того, как компонент вставлен в реальный DOM. К этому моменту Vue создал все DOM-узлы, привязал refs и выполнил первоначальный рендеринг. Поэтому this.$refs.refName гарантированно содержит ссылку на элемент (или компонент), если ref был указан в шаблоне.

Исключение: если ref динамический или привязан через v-if/v-for, элемент может отсутствовать в mounted до выполнения условий. В таких случаях используйте $nextTick или watch.

На практике

  • В created инициализируйте данные, подписывайтесь на события, делайте запросы к API - всё, что не требует DOM.
  • В mounted работайте с DOM: устанавливайте фокус, измеряйте размеры, подключайте сторонние библиотеки (например, Chart.js, D3).
  • Если нужно дождаться обновления DOM после изменения данных - используйте this.$nextTick(() => { ... }).
  • Для refs внутри v-for в mounted доступен массив элементов, но только после рендеринга списка.

Пример кода

<template>
  <div>
    <input ref="myInput" type="text" />
    <div v-if="show" ref="conditionalBlock">Условный блок</div>
  </div>
</template>

<script>
export default {
  data() {
    return { show: false }
  },
  created() {
    console.log(this.$refs.myInput) // undefined
    // Попытка установить фокус здесь упадёт с ошибкой
  },
  mounted() {
    console.log(this.$refs.myInput) // <input> элемент
    this.$refs.myInput.focus() // работает

    // Условный ref - пока недоступен
    console.log(this.$refs.conditionalBlock) // undefined

    this.show = true
    this.$nextTick(() => {
      console.log(this.$refs.conditionalBlock) // <div> элемент
    })
  }
}
</script>

Как отвечать на собеседовании

Начните с чёткого разграничения: created - до DOM, mounted - после. Подчеркните, что это не баг, а особенность жизненного цикла. Упомяните $nextTick как решение для отложенного доступа. Если спросят про Composition API - скажите, что логика та же: onMounted вместо mounted, onCreated (редко используется) вместо created. Добавьте, что для refs в v-for нужно учитывать асинхронность рендеринга.

Что проверяет интервьюер

  • Понимание жизненного цикла Vue и порядка вызова хуков.
  • Умение различать этапы инициализации данных и монтирования DOM.
  • Знание практических ограничений: refs не работают в created, $el недоступен.
  • Способность предложить альтернативы: $nextTick, watch с immediate, перенос логики в mounted.
  • Понимание разницы между Options API и Composition API в контексте refs.

Типичные ошибки

  • Попытка обратиться к this.$refs в created и получение undefined без понимания причины.
  • Использование $nextTick в created - это не решит проблему, так как DOM ещё не создан.
  • Забывание, что refs внутри v-if/v-for могут отсутствовать в mounted, если условие ложно или массив пуст.
  • Путаница между $refs и $el: $el - корневой элемент компонента, а $refs - коллекция помеченных элементов.
  • Использование mounted для логики, которая должна выполняться при каждом обновлении данных - для этого есть updated или watch.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью