dom манипуляции с DOM

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


Доступ к DOM через ref

В Vue 3 (на котором построен Quasar) доступ к элементам DOM осуществляется через директиву ref.

Пример использования:

<template>
  <div>
    <q-btn label="Изменить текст" @click="changeText" />
    <p ref="paragraph">Исходный текст</p>
  </div>
</template>

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

const paragraph = ref(null)

function changeText() {
  if (paragraph.value) {
    paragraph.value.textContent = 'Текст изменён'
  }
}
</script>

Ключевые моменты:

  • ref создаёт реактивную ссылку на DOM-элемент.
  • Доступ к DOM-элементу осуществляется через .value.
  • Проверка на null обязательна, так как элемент может быть ещё не смонтирован.

Директива v-bind и динамические атрибуты

Для динамического управления классами и стилями используются стандартные Vue-инструменты: v-bind:class и v-bind:style.

<template>
  <q-btn
    :class="{ 'bg-positive': isActive }"
    :style="{ fontSize: fontSize + 'px' }"
    label="Кнопка"
    @click="toggleActive"
  />
</template>

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

const isActive = ref(false)
const fontSize = ref(16)

function toggleActive() {
  isActive.value = !isActive.value
  fontSize.value += 2
}
</script>

Особенности:

  • Использование реактивных данных позволяет синхронизировать DOM без прямого обращения через document.querySelector.
  • Поддерживается условное добавление классов и inline-стилей.

Работа с событиями DOM

Quasar рекомендует использовать встроенные методы Vue для событий, однако прямое добавление слушателей к DOM тоже возможно.

<template>
  <div ref="container">Наведите курсор</div>
</template>

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

const container = ref(null)

function handleMouseOver() {
  container.value.style.backgroundColor = '#f0f0f0'
}

onMounted(() => {
  if (container.value) {
    container.value.addEventListener('mouseover', handleMouseOver)
  }
})

onBeforeUnmount(() => {
  if (container.value) {
    container.value.removeEventListener('mouseover', handleMouseOver)
  }
})
</script>

Рекомендации:

  • Всегда удалять слушатели в onBeforeUnmount для предотвращения утечек памяти.
  • Использовать Vue-события (@mouseover) для более чистого кода, если это возможно.

Интеграция с Quasar-компонентами

Quasar компоненты скрывают внутренние DOM-элементы, поэтому прямой доступ к ним требует использования ref на обёртке или getElement через $el:

<template>
  <q-input ref="input" label="Имя пользователя" />
</template>

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

const input = ref(null)

onMounted(() => {
  // Получение реального input внутри q-input
  const nativeInput = input.value.$el.querySelector('input')
  nativeInput.focus()
})
</script>

Важно:

  • $el предоставляет доступ к корневому DOM-элементу компонента.
  • Лучше избегать прямых манипуляций внутри Quasar-компонентов, если есть стандартные свойства и слоты.

Использование nextTick для безопасного изменения DOM

Изменения реактивных данных могут быть асинхронными. Для безопасной работы с DOM после обновления состояния применяется nextTick:

import { nextTick, ref } from 'vue'

const message = ref('Старый текст')

function updateMessage() {
  message.value = 'Новый текст'
  nextTick(() => {
    const paragraph = document.querySelector('p')
    paragraph.style.color = 'red'
  })
}

Задачи nextTick:

  • Гарантирует, что DOM полностью обновлён.
  • Предотвращает ошибки, связанные с попыткой манипулировать ещё не существующими элементами.

Динамическое создание элементов

Иногда требуется создать элементы программно, минуя шаблон. В Quasar это делается стандартным DOM API:

const newDiv = document.createElement('div')
newDiv.textContent = 'Новый блок'
newDiv.classList.add('q-pa-md', 'bg-grey-3')
document.body.appendChild(newDiv)

Советы:

  • Добавлять стили через классы Quasar (q-), чтобы сохранить единый стиль приложения.
  • Избегать частого создания DOM вручную — лучше использовать реактивные данные и v-for.

Анимации и эффекты при работе с DOM

Quasar интегрирует Vue Transition и CSS классы для анимаций:

<template>
  <transition name="fade">
    <div v-if="show" class="q-pa-md bg-primary text-white">
      Появляющийся блок
    </div>
  </transition>
  <q-btn label="Toggle" @click="show = !show" />
</template>

<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>

<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
</style>

Выводы:

  • Использование transition позволяет безопасно управлять появлением и исчезновением DOM-элементов.
  • Quasar CSS-классы упрощают визуальные эффекты без прямых манипуляций через JS.

Практические рекомендации

  • Минимизировать прямой доступ к DOM — использовать реактивные данные и слоты Quasar.
  • Применять ref и nextTick для синхронизации с реальным DOM.
  • Для сложных событий использовать onMounted и onBeforeUnmount с добавлением/удалением слушателей.
  • Сохранять стили и структуру компонентов через встроенные классы Quasar (q-) и атрибуты.

Эти методы обеспечивают стабильную и безопасную работу с DOM в масштабных Quasar-приложениях, сохраняя преимущества реактивности Vue.