Композиция компонентов

В Naive UI композиция компонентов является ключевым подходом для построения гибких и масштабируемых интерфейсов. Библиотека построена с учётом модульности, что позволяет создавать сложные UI из небольших, переиспользуемых компонентов. Основная идея композиции заключается в объединении нескольких компонентов, их вложенности и управлении состоянием через props, slots и events.

Использование слотов для гибкой композиции

Слоты в Naive UI позволяют вставлять внутрь компонентов произвольный контент, не нарушая их внутреннюю структуру. Основные типы слотов:

  • default slot – основной слот для вложенного контента.
  • named slot – именованный слот для более точного позиционирования элементов.
  • scoped slot – слот с передачей данных из дочернего компонента в родительский.

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

import { NCard, NButton } from 'naive-ui'

export default {
  setup() {
    return () => (
      <NCard title="Профиль пользователя">
        {{
          header: () => <h3>Информация о пользователе</h3>,
          default: () => <p>Имя: Иван Иванов</p>,
          footer: () => <NButton>Редактировать</NButton>
        }}
      </NCard>
    )
  }
}

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

Комбинирование компонентов через props

Props дают возможность настраивать поведение компонентов без изменения их внутренней логики. В Naive UI большинство компонентов поддерживают детальную настройку через объектные и булевы props.

Например, компонент NButton:

<NButton type="primary" size="large" disabled={false}>
  Сохранить
</NButton>

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

Передача событий и реактивное управление

Naive UI использует стандартные события Vue для передачи данных от дочернего компонента к родительскому. Основные механизмы:

  • onUpdate:prop – синхронизация значений props.
  • Кастомные события @event – реакция на действия пользователя.

Пример с компонентом NInput и двусторонней привязкой:

import { ref } from 'vue'
import { NInput } from 'naive-ui'

export default {
  setup() {
    const username = ref('')
    return () => (
      <NInput v-model:value={username.value} placeholder="Введите имя" />
    )
  }
}

Использование v-model:value автоматически связывает состояние родителя с дочерним компонентом, обеспечивая реактивное обновление интерфейса.

Создание комплексных компонентов через композицию

Композиция позволяет создавать новые компоненты на основе существующих, добавляя дополнительные слои логики или визуальные элементы. Например, создание кастомного UserCard:

import { NCard, NButton, NAvatar } from 'naive-ui'

export default {
  props: {
    user: Object
  },
  setup(props) {
    const editUser = () => {
      console.log('Редактирование пользователя', props.user.name)
    }

    return () => (
      <NCard>
        {{
          header: () => <h3>{props.user.name}</h3>,
          default: () => (
            <div>
              <NAvatar src={props.user.avatar} />
              <p>{props.user.email}</p>
            </div>
          ),
          footer: () => <NButton onCl ick={editUser}>Редактировать</NButton>
        }}
      </NCard>
    )
  }
}

Такой подход позволяет повторно использовать шаблон NCard и добавлять уникальную логику для каждого типа карточки.

Реактивные композиции с provide и inject

Для глубокой вложенности компонентов Naive UI поддерживает передачу данных через provide и inject, что особенно полезно для глобального состояния внутри композиции. Пример:

import { provide, inject, ref } from 'vue'

export const ThemeProvider = {
  setup(_, { slots }) {
    const theme = ref('light')
    provide('theme', theme)
    return () => slots.default()
  }
}

export const ThemedButton = {
  setup() {
    const theme = inject('theme')
    return () => <NButton type={theme.value === 'dark' ? 'info' : 'primary'}>Кнопка</NButton>
  }
}

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

Миксина и композиция функций

На уровне логики Naive UI и Vue 3 позволяет использовать композиционные функции для повторного использования реактивных блоков:

import { ref, computed } from 'vue'

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

Компонент может использовать useCounter для добавления функционала счётчика:

import { NButton } from 'naive-ui'
import { useCounter } from './useCounter'

export default {
  setup() {
    const { count, increment, double } = useCounter()
    return () => (
      <div>
        <p>Счётчик: {count.value}</p>
        <p>Удвоенное значение: {double.value}</p>
        <NButton onCl ick={increment}>Увеличить</NButton>
      </div>
    )
  }
}

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

Итог

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