Naive UI — это современная библиотека компонентов для Vue 3, ориентированная на удобство, производительность и лёгкость кастомизации. Одной из сильных сторон Naive UI является возможность создавать собственные компоненты, интегрирующиеся с её системой стилей и логики.
Создание собственного компонента начинается с импорта базовых функций Vue и компонентов Naive UI, если требуется их использование внутри нового компонента:
import { defineComponent, ref, computed } from 'vue';
import { NButton } from 'naive-ui';
Стандартная структура компонента включает:
Пример базового компонента:
export default defineComponent({
name: 'MyCustomButton',
props: {
label: {
type: String,
required: true
},
type: {
type: String,
default: 'primary'
}
},
emits: ['click'],
setup(props, { emit }) {
const handleClick = () => {
emit('click');
};
return { handleClick };
},
template: `
<n-button :type="type" @click="handleClick">{{ label }}</n-button>
`
});
В этом примере создаётся компонент MyCustomButton,
который оборачивает стандартный NButton и добавляет
обработку собственного события click.
Naive UI активно использует концепцию слотов для кастомизации содержимого компонентов. Слоты позволяют внедрять произвольное содержимое в заранее определённую структуру компонента:
export default defineComponent({
name: 'CardWithHeader',
props: {
title: String
},
setup() {},
template: `
<div class="card">
<div class="card-header">{{ title }}</div>
<div class="card-body">
<slot></slot>
</div>
<div class="card-footer">
<slot name="footer"></slot>
</div>
</div>
`
});
<slot> — основной слот для содержимого.<slot name="footer"> — именованный слот для
футера.Такой подход позволяет комбинировать базовые стили Naive UI с произвольной логикой.
Для управления состоянием в компоненте используется reactive, ref, computed. Важно сохранять совместимость с реактивностью Vue 3, чтобы компоненты Naive UI корректно реагировали на изменения:
export default defineComponent({
name: 'ToggleSwitch',
props: {
modelValue: Boolean
},
emits: ['update:modelValue'],
setup(props, { emit }) {
const isChecked = ref(props.modelValue);
const toggle = () => {
isChecked.value = !isChecked.value;
emit('update:modelValue', isChecked.value);
};
return { isChecked, toggle };
},
template: `
<n-switch v-model:checked="isChecked" @update:checked="toggle" />
`
});
v-model:checked связывает состояние компонента с
реактивной переменной.emit('update:modelValue') обеспечивает
поддержку двухсторонней привязки.Naive UI поддерживает темизацию и CSS-переменные, что позволяет адаптировать внешний вид компонента без изменения исходного кода:
.my-card {
--n-card-padding: 24px;
--n-card-border-radius: 12px;
background-color: var(--n-card-color, #fff);
}
Внутри компонента можно использовать классы с префиксом
my- для изоляции стилей, сохраняя совместимость с
глобальными стилями Naive UI.
В некоторых случаях требуется расширить стандартный компонент Naive UI. Это делается через композицию или наследование:
export default defineComponent({
name: 'AdvancedButton',
extends: NButton,
props: {
loading: Boolean
},
setup(props, { slots }) {
return () => (
<NButton type="primary" disabled={props.loading}>
{props.loading ? 'Loading...' : slots.default?.()}
</NButton>
);
}
});
Такой подход позволяет добавлять новые свойства, не переписывая базовый функционал.
При создании сложных компонентов рекомендуется:
Пример composable для управления формой:
import { reactive } from 'vue';
export function useForm(initialValues) {
const state = reactive({ ...initialValues });
const reset = () => Object.assign(state, initialValues);
return { state, reset };
}
В компоненте форма подключается так:
const { state, reset } = useForm({ name: '', email: '' });
Собственный компонент Naive UI обычно сочетает:
Такой подход обеспечивает масштабируемость и повторное использование, а также сохраняет согласованность с экосистемой Naive UI.