Naive UI предоставляет гибкий механизм работы с
компонентами тегов через n-tag и n-tag-group.
Особенно полезным является создание динамических тегов, когда список
элементов может изменяться в зависимости от пользовательского ввода или
данных с сервера.
n-tag – отдельный тег с текстом,
цветом и опциями удаления.n-tag-group – контейнер для группы
тегов, поддерживает динамическое добавление и удаление элементов.Простейший пример использования:
<template>
<n-tag-group>
<n-tag v-for="tag in tags" :key="tag" closable @close="removeTag(tag)">
{{ tag }}
</n-tag>
</n-tag-group>
</template>
<script setup>
import { ref } from 'vue'
const tags = ref(['Vue', 'JavaScript', 'Naive UI'])
function removeTag(tag) {
tags.value = tags.value.filter(t => t !== tag)
}
</script>
В этом примере каждый тег можно закрыть, а список tags
динамически обновляется.
Для динамического добавления часто используют текстовое поле
(n-input) и кнопку. В Naive UI можно реализовать так:
<template>
<n-input v-model:value="newTag" @keyup.enter="addTag" placeholder="Введите новый тег" />
<n-button @click="addTag">Добавить</n-button>
<n-tag-group>
<n-tag v-for="tag in tags" :key="tag" closable @close="removeTag(tag)">
{{ tag }}
</n-tag>
</n-tag-group>
</template>
<script setup>
import { ref } from 'vue'
const tags = ref(['Vue', 'JavaScript'])
const newTag = ref('')
function addTag() {
const value = newTag.value.trim()
if (value && !tags.value.includes(value)) {
tags.value.push(value)
}
newTag.value = ''
}
function removeTag(tag) {
tags.value = tags.value.filter(t => t !== tag)
}
</script>
Особенности реализации:
trim() предотвращает добавление пустых
тегов.!tags.value.includes(value) исключает
дубли.@keyup.enter позволяет добавлять тег
по нажатию Enter.n-tag поддерживает кастомизацию через свойства:
type – визуальный тип (info,
success, warning, error,
default)color – собственный цвет фонаsize – размер (small, medium,
large)Пример динамического изменения цвета в зависимости от контента:
<n-tag
v-for="tag in tags"
:key="tag"
closable
:color="tagColor(tag)"
@close="removeTag(tag)"
>
{{ tag }}
</n-tag>
<script setup>
function tagColor(tag) {
switch(tag.toLowerCase()) {
case 'vue': return '#42b883'
case 'javascript': return '#f7df1e'
default: return '#d9d9d9'
}
}
</script>
Иногда нужно ограничить количество тегов, чтобы не перегружать интерфейс:
<n-tag-group>
<n-tag
v-for="(tag, index) in tags.slice(0, maxTags)"
:key="tag"
closable
@close="removeTag(tag)"
>
{{ tag }}
</n-tag>
<span v-if="tags.length > maxTags">+{{ tags.length - maxTags }} ещё</span>
</n-tag-group>
<script setup>
const maxTags = 3
</script>
slice(0, maxTags) ограничивает количество отображаемых
тегов.+N ещё показывает количество скрытых
тегов.Для более сложных случаев, например с тегами, имеющими идентификатор и текст:
<n-tag-group>
<n-tag
v-for="tag in tags"
:key="tag.id"
closable
@close="removeTag(tag.id)"
:type="tag.type"
>
{{ tag.label }}
</n-tag>
</n-tag-group>
<script setup>
const tags = ref([
{ id: 1, label: 'Vue', type: 'success' },
{ id: 2, label: 'Naive UI', type: 'info' }
])
function removeTag(id) {
tags.value = tags.value.filter(t => t.id !== id)
}
</script>
id, что облегчает
удаление.type позволяет визуально выделять разные категории
тегов.Для редактирования текста тегов можно использовать событие
@click и модальное окно или n-input внутри
n-tag:
<n-tag-group>
<n-tag
v-for="tag in tags"
:key="tag.id"
closable
@close="removeTag(tag.id)"
>
<n-input v-model:value="tag.label" size="small" />
</n-tag>
</n-tag-group>
v-model.Для интеграции с сервером динамические теги можно загружать и синхронизировать через API:
import axios from 'axios'
async function fetchTags() {
const response = await axios.get('/api/tags')
tags.value = response.data
}
async function saveTags() {
await axios.post('/api/tags', tags.value)
}
fetchTags() загружает исходный набор тегов.saveTags() сохраняет изменения на сервере.v-model.v-for с уникальным :key для
корректного обновления DOM.id и label.Этот подход позволяет строить гибкие интерфейсы с динамическими тегами, которые легко масштабируются, интегрируются с сервером и адаптируются под любые пользовательские сценарии.