логотип PurpleSchool
логотип PurpleSchool

3 способа манипулирования DOM на Vue

Автор

Олег Марков

Введение

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

В этой статье я расскажу о трех эффективных способах манипулирования DOM во Vue-приложениях, разберу их на примерах и поясню, когда стоит выбирать тот или иной способ, а также на что обратить внимание в плане производительности и читаемости кода.

Я сфокусируюсь на следующих методах:

  1. Управление отображением с помощью v-if и v-show
  2. Доступ к элементам через $refs
  3. Рендеринг HTML через директиву v-html

Давайте рассмотрим эти подходы подробнее, чтобы понять их возможности и тонкости.

Управление отображением с помощью v-if и v-show

Что такое v-if и v-show

Vue предлагает специальные директивы — v-if и v-show — которые позволяют контролировать присутствие элементов в DOM на основе состояния ваших данных.

  • v-if полностью удаляет или добавляет элемент в DOM в зависимости от условия.
  • v-show всегда оставляет элемент в DOM, но управляет его видимостью через CSS-свойство display.

Использование этих возможностей важно, когда требуется динамически показывать, скрывать или удалять элементы в зависимости от состояния приложения.

Пример использования v-if

Смотрите, вот так вы можете показать или удалить элемент из DOM в зависимости от состояния:

<template>
  <div>
    <button @click="visible = !visible">Показать/скрыть уведомление</button>
    <div v-if="visible">
      Важное уведомление!
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      visible: false // По умолчанию сообщение скрыто
    }
  }
}
</script>

// Когда вы кликаете по кнопке, переменная visible меняется. Если значение становится true, элемент добавляется в DOM, иначе — удаляется полностью.

Как работает v-show

А вот пример с v-show:

<template>
  <div>
    <button @click="show = !show">Показать/скрыть блок</button>
    <div v-show="show">
      Я просто скрываю себя с помощью CSS.
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      show: false // По умолчанию блок скрыт
    }
  }
}
</script>

// Здесь элемент всегда присутствует в DOM, но видимость управляется стилем display: none. Это быстрее при частых переключениях.

Когда использовать v-if, а когда v-show

Обратите внимание, что v-if стоит выбирать, если элемент появляется или исчезает редко и для вас важно, чтобы его не было в DOM вообще.

Для частого переключения видимости лучше подходит v-show — элемент всегда в DOM, и переключение происходит здесь и сейчас, быстро, без пересоздания компонента.

Групповое управление с помощью

Vue разрешает использовать директивы на контейнере <template>, если хотите показывать или скрывать сразу несколько элементов без лишней обертки:

<template>
  <div>
    <button @click="showDetails = !showDetails">Показать детали</button>
    <template v-if="showDetails">
      <p>Детальная информация A</p>
      <p>Детальная информация B</p>
    </template>
  </div>
</template>

// Так вы не добавляете в DOM ненужные уровни вложенности.

Как еще можно усложнить пример

Вложенное использование v-if и динамические условия:

<template>
  <div>
    <button @click="mode = 'a'">Режим A</button>
    <button @click="mode = 'b'">Режим B</button>

    <div v-if="mode === 'a'">
      Сейчас выбран режим А
    </div>
    <div v-else-if="mode === 'b'">
      Сейчас выбран режим B
    </div>
    <div v-else>
      Ни один режим не выбран
    </div>
  </div>
</template>

// Можно легко делать сложные переключатели на основе состояния.

Доступ к DOM-элементам через $refs

Что такое $refs

Vue позволяет создавать специальные ссылки на элементы внутри шаблона с помощью атрибута ref. Если вам нужно получить прямой доступ к DOM-элементу или экземпляру дочернего компонента — используйте $refs.

Обычно такой подход нужен, когда вам нужно программно управлять фокусом, выделением текста, прокруткой, запускать анимации или интегрироваться с нелинейной сторонней библиотекой.

Как объявить ref и использовать $refs

Давайте посмотрим, как это сделать:

<template>
  <div>
    <input ref="myInput" type="text">
    <button @click="focusInput">Фокус на поле ввода</button>
  </div>
</template>

<script>
export default {
  methods: {
    focusInput() {
      // Здесь мы обращаемся к DOM-элементу по ref и вызываем метод focus
      this.$refs.myInput.focus();
    }
  }
}
</script>

// При клике на кнопку input получает фокус. Это очень удобно для автофокуса или кастомных взаимодействий с элементами.

// Использовать $refs желательно только когда нельзя обойтись стандартными средствами Vue и реактивных данных.

Получение DOM-элемента или компонента через $refs

Если на элементе стоит ref, через this.$refs.refName вы получите DOM-элемент или экземпляр компонента.

  • Если это обычный DOM-элемент, придет ссылка на этот элемент, как в примере выше.
  • Если это дочерний компонент, получите экземпляр Vue-компонента:
<template>
  <child-component ref="child"></child-component>
  <button @click="callChildMethod">Запустить метод дочернего компонента</button>
</template>

<script>
export default {
  methods: {
    callChildMethod() {
      // Вызываем публичный метод у дочернего компонента
      this.$refs.child.someMethodFromChild();
    }
  }
}
</script>

// $refs отлично подходит для управления сложной логикой, где требуется прямой доступ к внутреннему API HTML-элементов или компонентов.

Массив $refs

Если вы используете рефы внутри v-for, то this.$refs.<имя> будет массивом:

<template>
  <ul>
    <li v-for="item in items" :key="item.id" :ref="setRefs">{{ item.name }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: [{ id: 1, name: 'One' }, { id: 2, name: 'Two' }]
    }
  },
  methods: {
    setRefs(el) {
      // Vue автоматически собирает массив рефов, если один и тот же ref указывается несколько раз
    }
  },
  mounted() {
    // Теперь this.$refs.setRefs — массив элементов <li>
    this.$refs.setRefs.forEach(li => {
      // Можно добавить стили или обработчики каждому элементу
    });
  }
}
</script>

// $refs довольно гибкий, но его не стоит использовать для постоянного доступа к данным компонентов, иначе структура может стать нечитаемой.

Когда избегать $refs

$refs нужно использовать там, где действительно требуется взаимодействие с конкретными DOM-элементами. Для абстрагированного управления отображением желательно использовать реактивные данные Vue.

Рендеринг HTML с помощью v-html

Для чего нужен v-html

Если вам нужно отобразить кусок HTML, полученный динамически (например, из API или настроек), Vue предлагает директиву v-html. Она вставляет заданную строку как HTML, а не как текст. Вот пример:

<template>
  <div>
    <div v-html="rawHtml"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      rawHtml: '<b>Это выделено жирным!</b>' // HTML-код, который мы хотим отобразить
    }
  }
}
</script>

// В отличие от {{ rawHtml }}, где HTML выводится как текст, v-html реально создает разметку в DOM.

Особенности и предостережения

  • Никогда не вставляйте в v-html данные, поступившие от пользователя или ненадежных источников, без санитации. Иначе ваш сайт станет уязвим для XSS-атак.
  • Vue не применяет дополнительные обработки — то, что вы передали в v-html, то попадет в DOM.

Реальный случай использования: описание из CMS

Представьте, что вы выводите описание товара из CMS, в котором могут быть ссылки или выделения:

<template>
  <div>
    <div v-html="productDescription"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      productDescription: '<p>Этот <a href="#">товар</a> — отличный выбор!</p>'
    }
  }
}
</script>

// Контент будет "оживать" и корректно отображаться.

Можно ли динамически добавлять компоненты через v-html?

Обратите внимание, что Vue не обрабатывает шаблоны внутри v-html как свои компоненты — внутренности не связываются с вашим реактивным состоянием. Получатся просто “сырые” DOM-узлы, которыми Vue дальше не управляет.

Заключение

В обработке DOM во Vue есть несколько проверенных подходов, которые закрывают практически все задачи по управлению разметкой и реагированию на события пользователя.

  • Через v-if и v-show вы удобно реагируете на изменения состояния, добавляя и убирая блоки из DOM.
  • С помощью $refs вы напрямую управляете HTML-элементами — идеально для случаев, когда стандартных реактивных средств недостаточно.
  • С директивой v-html можно быстро встраивать динамические фрагменты HTML, поступающие из внешних источников.

Важно использовать эти способы осознанно, выбирая наиболее подходящий для конкретной задачи: экономить ресурсы, поддерживать безопасность и читаемость кода.

Хорошая архитектура Vue-приложения всегда базируется на принципах реактивности — прямое взаимодействие с DOM стоит применять только там, где это действительно необходимо.

Частозадаваемые технические вопросы и ответы

Как получить доступ к родительскому компоненту из дочернего?

Используйте свойство $parent внутри дочернего компонента. Например, this.$parent. Однако стоит помнить, что изменение родителя таким способом увеличивает связанность компонентов и усложняет поддержку. Лучше обмениваться данными через props и события, а прямой доступ применять только при необходимости.

Как анимировать появление элементов при использовании v-if или v-show?

Добавьте обертку <transition>, внутри которой размещайте элементы с v-if или v-show:

<transition name="fade">
  <div v-if="visible">...</div>
</transition>

Затем определите классыAnimations CSS для fade-enter-active, fade-leave-active и т.д. Vue таким образом будет применять плавные переходы при появлении и исчезновении.

Можно ли управлять DOM-подсистемой сторонней библиотеки из Vue?

Да, но используйте для этого хуки жизненного цикла mounted или updated и $refs для доступа к DOM-узлам. Подключайте сторонние виджеты только после того, как DOM уже создан, чтобы избежать ошибок работы с еще несуществующими элементами.

Как безопасно вставлять HTML, если нужно использовать пользовательский ввод?

Перед передачей данных в v-html обязательно очищайте их с помощью надежной библиотеки для "санитации" HTML, например, dompurify или sanitize-html. Это защитит приложение от XSS-атак.

Что делать, если $refs возвращает undefined?

Убедитесь, что компонент или элемент действительно смонтирован. Получить $refs можно только после отработки хука mounted. Если доступ к $refs нужен сразу, дождитесь этого этапа жизненного цикла.


Стрелочка влевоРабота с динамическими компонентами и данными в VueРуководство по div во VueСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийNuxt JS и Vue 3 для SSR приложенийКак организовать страницы и маршруты в проекте на VueСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхИспользование scoped стилей для изоляции CSS в компонентах VueПрименение script setup синтаксиса в Vue 3 для упрощения компонентов3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

Отправить комментарий