Vue: директивы и composition API

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

v-bind используется для динамической привязки атрибутов элементов к свойствам компонента:

<template>
  <img v-bind:src="imageUrl" alt="Dynamic Image">
</template>

<script>
export default {
  data() {
    return {
      imageUrl: 'https://example.com/image.jpg'
    }
  }
}
</script>

Сокращённая запись :src="imageUrl" делает синтаксис более компактным.

v-model обеспечивает двустороннюю привязку данных, чаще всего к формам:

<input v-model="username" placeholder="Введите имя">
<p>Привет, {{ username }}</p>

Здесь значение username автоматически синхронизируется с содержимым поля ввода.

v-if, v-else-if, v-else управляют условным отображением элементов:

<p v-if="isLoggedIn">Добро пожаловать!</p>
<p v-else>Пожалуйста, войдите в систему</p>

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

v-for применяется для итераций:

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

key необходим для корректного отслеживания элементов при обновлении списка.


Создание собственных директив

Vue позволяет создавать кастомные директивы с полным контролем над поведением DOM. Директива может содержать хуки: bind, inserted, update, componentUpdated, unbind.

Пример простой директивы для фокуса на элементе при монтировании:

Vue.directive('focus', {
  inserted(el) {
    el.focus()
  }
})

Использование:

<input v-focus>

Директивы можно расширять, передавая аргументы и значения через v-directive:argument="value".


Composition API: реактивность и управление состоянием

Composition API — современный способ организации логики компонентов. Основные функции: ref, reactive, computed, watch.

ref создаёт реактивное примитивное значение:

import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const increment = () => count.value++
    return { count, increment }
  }
}

Для доступа к значению используется .value. Это важно для всех примитивов (number, string, boolean).

reactive создаёт реактивный объект:

import { reactive } from 'vue'

export default {
  setup() {
    const state = reactive({
      user: { name: 'Alice', age: 25 },
      loggedIn: false
    })

    const login = () => state.loggedIn = true

    return { state, login }
  }
}

Реактивность распространяется на все вложенные свойства объекта.


Вычисляемые свойства и наблюдатели

computed создаёт вычисляемые свойства, которые автоматически обновляются при изменении зависимостей:

import { ref, computed } from 'vue'

export default {
  setup() {
    const firstName = ref('Alice')
    const lastName = ref('Smith')

    const fullName = computed(() => `${firstName.value} ${lastName.value}`)

    return { firstName, lastName, fullName }
  }
}

watch позволяет реагировать на изменения реактивных данных:

import { ref, watch } from 'vue'

export default {
  setup() {
    const count = ref(0)

    watch(count, (newVal, oldVal) => {
      console.log(`count изменился с ${oldVal} на ${newVal}`)
    })

    return { count }
  }
}

Организация логики компонентов с Composition API

Composition API облегчает повторное использование логики через функции setup и пользовательские composables:

// useCounter.js
import { ref } from 'vue'

export function useCounter() {
  const count = ref(0)
  const increment = () => count.value++
  return { count, increment }
}

// В компоненте
import { useCounter } from './useCounter'

export default {
  setup() {
    const { count, increment } = useCounter()
    return { count, increment }
  }
}

Composables позволяют создавать модульную, тестируемую и легко поддерживаемую логику, отделяя её от структуры шаблона.


Интеграция директив и Composition API

Директивы и Composition API отлично дополняют друг друга. В setup можно создавать реактивные состояния и передавать их в кастомные директивы через аргументы или значение:

// v-color.js
export default {
  mounted(el, binding) {
    el.style.color = binding.value
  },
  updated(el, binding) {
    el.style.color = binding.value
  }
}

// В компоненте
import colorDirective from './v-color'

export default {
  directives: { color: colorDirective },
  setup() {
    const textColor = ref('red')
    return { textColor }
  }
}

<!-- В шаблоне -->
<p v-color="textColor">Текст с динамическим цветом</p>

Такой подход позволяет объединять реактивность Composition API с управлением DOM через директивы, сохраняя чистоту кода и гибкость архитектуры.