用法
accordion
accordion prop 属性:
items属性: 这是定义手风琴内容的数组。数组中的每个对象代表一个可折叠项,你可以为每个项设置label(标题)、content(内容)、icon、trailingIcon、disabled等。type属性:- 'single' (默认): 一次只能展开一个项。
- 'multiple': 可以同时展开多个项。
default-value或v-model: 控制手风琴项的默认展开状态或通过响应式数据进行双向绑定。ui属性: 这是 Nuxt UI 组件的一个强大特性,允许你传递一个对象,其中包含 Tailwind CSS 类,用于深度定制手风琴的各个子元素(如root、item、header、trigger、content、body等)。这使得组件的样式高度可定制,无需修改其内部结构。- 插槽 (Slots):
- 默认插槽 (
#default): 如果你需要完全自定义手风琴项的标题部分,可以使用这个作用域插槽。它会暴露item,index,open数据。 leading插槽 (#leading): 自定义标题左侧的内容,通常用于图标。trailing插槽 (#trailing): 自定义标题右侧的内容,通常用于箭头或切换图标。content插槽 (#content): 自定义手风琴项的内容区域。body内容主体插槽 (#body): 类似content,但通常用于包裹默认内容,并保留body样式。- 自定义具名插槽 (
#{{ item.slot }}): 如果你在items数组的某个项中设置了slot: 'myCustomSlotName',你可以使用#myCustomSlotName或#myCustomSlotName-body来为该特定项提供完全自定义的内容。
- 默认插槽 (
Items
使用 items prop 属性,它是一个对象数组,具有以下属性:
label?: stringicon?: stringtrailingIcon?: stringcontent?: stringvalue?: stringdisabled?: booleanslot?: stringclass?: anyui?: { item?: ClassNameValue, header?: ClassNameValue, trigger?: ClassNameValue, leadingIcon?: ClassNameValue, label?: ClassNameValue, trailingIcon?: ClassNameValue, content?: ClassNameValue, body?: ClassNameValue }
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion :items="items" />
</template>
多选 (Multiple)
将 type 属性设置为 multiple 以允许同时激活多个项目。默认为 single。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion type="multiple" :items="items" />
</template>
可折叠 (Collapsible)
当 type 为 single 时,您可以将 collapsible 属性设置为 false 以防止活动项目折叠。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion :collapsible="false" :items="items" />
</template>
卸载 (Unmount)
使用 unmount-on-hide 属性可以防止手风琴折叠时内容被卸载。默认为 true。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: '您无需做任何事,@nuxt/icon 会自动处理。'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: '从您的 Tailwind CSS 主题中选择一个主色(primary)和一个中性色(neutral)。'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: '您可以通过使用 `class` / `ui` 属性或在 app.config.ts 中自定义组件。'
}
])
</script>
<template>
<UAccordion :unmount-on-hide="false" :items="items" />
</template>
禁用 (Disabled)
使用 disabled 属性禁用整个手风琴。
您还可以通过在项目对象中使用 disabled 属性来禁用特定项目。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.',
disabled: true
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
</script>
<template>
<UAccordion disabled :items="items" />
</template>
尾部图标 (Trailing Icon)
使用 trailing-icon 属性自定义每个项目的尾部 Icon。默认为 i-lucide-chevron-down。
trailingIcon 属性为特定项目设置图标。<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = ref<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: '您无需做任何事,@nuxt/icon 会自动处理。',
trailingIcon: 'i-lucide-plus'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: '从您的 Tailwind CSS 主题中选择一个主色(primary)和一个中性色(neutral)。'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: '您可以通过使用 `class` / `ui` 属性或在 `app.config.ts` 中自定义组件。'
}
])
</script>
<template>
<UAccordion trailing-icon="i-lucide-arrow-down" :items="items" />
</template>
示例
控制活动项目
您可以通过使用 default-value 属性或使用 v-model 指令结合数据项的索引来控制活动项目。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
]
const active = ref('0')
// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
setInterval(() => {
active.value = String((Number(active.value) + 1) % items.length)
}, 2000)
})
</script>
<template>
<UAccordion v-model="active" :items="items" />
</template>
value。type="multiple" 时,请确保向 default-value 属性或 v-model 指令传递一个数组。拖放 (Drag and Drop)
使用来自 @vueuse/integrations 的 useSortable 可组合项,以在手风琴上启用拖放功能。此集成封装了 Sortable.js,以提供无缝的拖放体验。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
import { useSortable } from '@vueuse/integrations/useSortable'
const items = shallowRef<AccordionItem[]>([
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
])
const accordion = useTemplateRef<HTMLElement>('accordion')
useSortable(accordion, items, {
animation: 150
})
</script>
<template>
<UAccordion ref="accordion" :items="items" />
</template>
使用 body 插槽
使用 #body 插槽自定义每个项目的主体。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{
label: 'Icons',
icon: 'i-lucide-smile'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book'
},
{
label: 'Components',
icon: 'i-lucide-box'
}
]
</script>
<template>
<UAccordion :items="items">
<template #body="{ item }">
This is the {{ item.label }} panel.
</template>
</UAccordion>
</template>
#body 插槽包含一些预定义样式,如果您想从头开始,请使用 #content slot。使用 content 插槽
使用 #content 插槽自定义每个项目的内容。
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{
label: 'Icons',
icon: 'i-lucide-smile'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book'
},
{
label: 'Components',
icon: 'i-lucide-box'
}
]
</script>
<template>
<UAccordion :items="items">
<template #content="{ item }">
<p class="pb-3.5 text-sm text-muted">
This is the {{ item.label }} panel.
</p>
</template>
</UAccordion>
</template>
使用自定义插槽
使用 slot 属性自定义特定数据项使用的插槽。
您将可以访问以下插槽:
#{{ item.slot }}#{{ item.slot }}-body
#{{ item.slot }}-body 比 #{{ item.slot }} 插槽多包含一些预定义样式。如果想从头开始,请使用 #{{ item.slot }}。<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = [
{
label: 'Icons',
icon: 'i-lucide-smile',
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
},
{
label: 'Colors',
icon: 'i-lucide-swatch-book',
slot: 'colors' as const,
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
},
{
label: 'Components',
icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
}
] satisfies AccordionItem[]
</script>
<template>
<UAccordion :items="items">
<template #colors="{ item }">
<p class="text-sm pb-3.5 text-primary">
{{ item.content }}
</p>
</template>
</UAccordion>
</template>
内容渲染的优先级流程
以下是内容渲染的优先级顺序,从高到低:
- 数据项特定的
item.slot(不带-body后缀):如果item.slot已定义,并且父组件提供了与该确切名称匹配的具名插槽。 - 通用
content插槽:如果没有使用item.slot(或没有为其提供匹配的插槽),但父组件提供了通用的content具名插槽。 - 数据项特定的
item.slot-body(带-body后缀):如果上述两者都不适用,但item.slot已定义,并且父组件提供了与item.slot + '-body'匹配的具名插槽。 - 通用
body插槽:如果上述三者都不适用,但父组件提供了通用的body插槽。 item.content字符串:如果父组件绝对没有提供任何插槽,则显示item.content中的原始字符串。
content 类型插槽比包含 body 插槽可定制性更多。使用自定义 ui
<script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items1: AccordionItem[] = [
{
label: '什么是 Nuxt UI?',
icon: 'iconamoon:question-mark-circle-light',
content: 'Nuxt UI 是一个基于 Vue 3 和 Tailwind CSS 的开源 UI 库,旨在为 Nuxt 应用程序提供可组合、无障碍和高度可定制的 UI 组件。'
},
{
label: '如何开始使用 Nuxt UI?',
icon: 'lets-icons:arrow-right-light',
content: '您可以通过在 Nuxt 项目中安装 `@nuxt/ui` 模块并将其添加到 `nuxt.config.ts` 来开始使用。'
},
{
label: 'Nuxt UI 支持哪些主题?',
icon: 'ph:paint-brush-light',
content: 'Nuxt UI 提供开箱即用的深色和浅色主题,并且所有组件都可通过 `ui` 属性或 `app.config.ts` 进行高度定制。'
}
];
const items2: AccordionItem[] = [
{
label: '核心原则',
icon: 'stash:light-bulb-light',
content: '我们的设计理念是简洁、高效和可扩展性。'
},
{
label: '创新技术',
icon: 'heroicons-outline:sparkles',
content: '我们积极探索并应用最新的前端技术。'
},
{
label: '用户体验',
icon: 'fa6-regular:face-smile',
content: '始终将用户体验放在首位,致力于提供流畅和直观的界面。'
}
];
const items3: AccordionItem[] = [
{
label: '默认样式项',
content: '这个项会继承父级 UAccordion 的 UI 样式。'
},
{
label: '定制背景色和文本色',
content: '这个项有其独特的背景和文本颜色。',
ui: { // 这个 ui 属性只应用于当前这个 AccordionItem
item: 'bg-green-100 dark:bg-green-900 border-green-300 dark:border-green-700',
header: 'bg-green-200 dark:bg-green-800 text-green-900 dark:text-green-100 hover:!bg-green-300 dark:hover:!bg-green-700', // 注意 ! 用于提高优先级
content: 'bg-green-50 dark:bg-green-950 text-green-800 dark:text-green-200'
}
},
{
label: '定制图标和触发器',
icon: 'iconamoon:star-light',
content: '这个项有定制的图标和触发器样式。',
ui: {
leadingIcon: 'text-yellow-500', // 仅此项的左侧图标变为黄色
trigger: 'p-6 font-mono text-purple-700 dark:text-purple-300' // 仅此项的触发器字体和颜色
}
}
];
</script>
<template>
<div class="p-4">
<h2 class="text-2xl font-bold mb-6">UAccordion UI 属性示例</h2>
<div class="space-y-8">
<div>
<h3 class="text-xl font-semibold mb-4">示例 1: 基本样式定制</h3>
<UAccordion
:items="items1"
:ui="{
// root: 'bg-white dark:bg-gray-900 shadow-lg rounded-xl', // 整个手风琴容器的样式
item: 'border-b border-gray-200 dark:border-gray-700 last:border-b-0', // 每个手风琴项的底部边框
header: 'hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors duration-200', // 头部悬停效果
trigger: 'p-4 flex items-center justify-between w-full text-left', // 触发器内边距和对齐
content: 'px-4 pb-4 text-gray-700 dark:text-gray-300' // 内容区域的内边距和文本颜色
}"
/>
</div>
<div>
<h3 class="text-xl font-semibold mb-4">示例 2: 深度定制与特定项样式</h3>
<UAccordion
:items="items2"
type="multiple"
:ui="{
// 全局样式
root: 'bg-white dark:bg-gray-900 rounded-lg overflow-hidden border border-purple-300 dark:border-purple-700',
item: 'border-b border-purple-200 dark:border-purple-800 last:border-b-0',
header: 'bg-purple-50 dark:bg-purple-950 text-purple-800 dark:text-purple-200',
trigger: 'p-5 font-bold text-lg',
leadingIcon: 'text-purple-600 dark:text-purple-400',
trailingIcon: 'text-purple-600 dark:text-purple-400 transition-transform duration-200 ui-expanded:rotate-180',
label: 'tracking-wide', // 字间距
content: 'px-5 py-3 bg-purple-100 dark:bg-purple-900 text-purple-900 dark:text-purple-100'
}"
/>
</div>
<div>
<h3 class="text-xl font-semibold mb-4">示例 3: 结合 `item.ui` 定制单个项</h3>
<UAccordion
:items="items3"
:ui="{
item: 'border-b border-gray-200 dark:border-gray-700 last:border-b-0'
}"
/>
</div>
</div>
</div>
</template>
- 可以通过
props.class定义根组件的样式。 - 可以通过
props.ui覆盖组件的默认样式。 - 可以通过
item.class定义当前手风琴项目的根样式。 - 可以通过
item.ui覆盖当前手风琴项目默认样式。
API
Props
| Prop | Default | Type |
|---|---|---|
as |
|
The element or component this component should render as. |
items |
| |
trailingIcon |
|
The icon displayed on the right side of the trigger. |
labelKey |
|
The key used to get the label from the item. |
collapsible |
|
When type is "single", allows closing content when clicking trigger for an open item. When type is "multiple", this prop has no effect. |
defaultValue |
The default active value of the item(s). Use when you do not need to control the state of the item(s). | |
modelValue |
The controlled value of the active item(s). Use this when you need to control the state of the items. Can be binded with | |
type |
|
Determines whether a "single" or "multiple" items can be selected at a time. This prop will overwrite the inferred type from |
disabled |
|
When |
unmountOnHide |
|
When |
ui |
|
Slots
| Slot | Type |
|---|---|
leading |
|
default |
|
trailing |
|
content |
|
body |
|
Emits
| Event | Type |
|---|---|
update:modelValue |
|
update:modelValue 事件是 UAccordion 组件向父组件 “报告” 其内部展开状态变化的方式,使得父组件可以响应并控制手风琴的行为。UAccordion 组件自身并不直接在其内部逻辑中显式地调用 emits('update:modelValue', ...),而是依赖于其内部使用的 reka-ui 库的 AccordionRoot 组件来发出这个事件。AccordionRoot 是一个 Radix Vue 或类似无头 UI 库的组件,它会管理手风琴的展开/折叠状态,并在状态改变时发出 update:modelValue 事件。update:modelValue 事件的使用场景
update:modelValue 事件主要用于:
- 双向绑定(
v-model):这是最常见和推荐的用法。 - 单向数据流控制(
:model-value和@update:model-value):当你需要更精细地控制手风琴的展开状态时。
modelValue 的值会根据 type 属性的不同而有所区别:
- 当
type="single"(单选模式) 时,modelValue会是一个 字符串 (对应当前展开项的value属性) 或 null。 - 当
type="multiple"(多选模式) 时,modelValue会是一个 字符串数组 (对应所有展开项的value属性)。
示例用法
假设你有一个手风琴,你想在父组件中控制哪个项是展开的,并在展开状态改变时执行一些逻辑。
- 使用
v-model(推荐)
这是最简洁的用法。
<template>
<div>
<h2>使用 v-model 控制手风琴</h2>
<p>当前展开项的值: {{ activeAccordionItem }}</p>
<UAccordion
v-model="activeAccordionItem"
:items="accordionItems"
type="single"
/>
<h2>使用 v-model 控制多个手风琴</h2>
<p>当前展开项的值 (多选): {{ activeMultipleAccordionItems }}</p>
<UAccordion
v-model="activeMultipleAccordionItems"
:items="accordionItems"
type="multiple"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { AccordionItem } from '@nuxt/ui'
const accordionItems: AccordionItem[] = [
{ label: '服务条款', content: '这里是服务条款的详细内容。', value: 'terms' },
{ label: '隐私政策', content: '这里是隐私政策的详细内容。', value: 'privacy' },
{ label: '联系方式', content: '您可以通过邮箱或电话联系我们。', value: 'contact' }
];
// 单选模式的 v-model
const activeAccordionItem = ref<string | null>('privacy'); // 初始展开 'privacy'
// 多选模式的 v-model
const activeMultipleAccordionItems = ref<string[]>(['terms']); // 初始展开 'terms'
</script>
解释:
v-model="activeAccordionItem"等同于:model-value="activeAccordionItem"@update:modelValue="activeAccordionItem = $event"。- 当用户点击手风琴项使其展开或折叠时,底层的
AccordionRoot会发出update:modelValue事件,事件的载荷就是新的modelValue(当前展开项的value或value数组)。 - Vue 的
v-model语法会自动捕获这个事件并更新activeAccordionItem这个ref。
- 使用
:model-value和@update:modelValue(更精细控制)
当你需要截获 update:modelValue 事件并执行额外逻辑时,可以使用这种方式。
<template>
<div>
<h2>使用 @update:modelValue 监听手风琴状态</h2>
<p>当前展开项: {{ currentActiveItem }}</p>
<p>上一个操作: {{ lastAction }}</p>
<UAccordion
:model-value="currentActiveItem"
@update:model-value="handleAccordionChange"
:items="accordionItems"
type="single"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { AccordionItem } from '@nuxt/ui'
const accordionItems: AccordionItem[] = [
{ label: '产品介绍', content: '我们的产品功能强大,操作简便。', value: 'product' },
{ label: '技术支持', content: '遇到任何问题,请联系我们的技术支持团队。', value: 'support' },
{ label: '合作伙伴', content: '期待与您建立长期的合作关系。', value: 'partners' }
];
const currentActiveItem = ref<string | null>('product');
const lastAction = ref<string>('无');
const handleAccordionChange = (newValue: string | string[]) => {
console.log('手风琴状态改变了!新值:', newValue);
// 根据新旧值判断是展开还是折叠
if (Array.isArray(newValue)) { // 多选模式
if (currentActiveItem.value && !newValue.includes(currentActiveItem.value[0])) { // 假设只关心第一个元素
lastAction.value = `折叠了: ${currentActiveItem.value[0]}`;
} else if (newValue.length > (currentActiveItem.value as string[]).length) {
const newOpened = newValue.filter(val => !(currentActiveItem.value as string[]).includes(val));
lastAction.value = `展开了: ${newOpened.join(', ')}`;
} else {
lastAction.value = '状态更新';
}
} else { // 单选模式
if (newValue === null) {
lastAction.value = `折叠了: ${currentActiveItem.value}`;
} else if (currentActiveItem.value === null) {
lastAction.value = `展开了: ${newValue}`;
} else {
lastAction.value = `从 ${currentActiveItem.value} 切换到 ${newValue}`;
}
}
// 更新组件的 active 状态,这是必须的,因为我们没有使用 v-model
currentActiveItem.value = newValue as string | null;
// 你可以在这里执行其他逻辑,例如发送分析事件,加载数据等
if (newValue === 'support') {
console.log('用户展开了技术支持,准备加载相关文档...');
// loadSupportDocs();
}
};
</script>
解释:
- 我们使用
:model-value="currentActiveItem"来向UAccordion传递当前展开的状态。 - 我们通过
@update:model-value="handleAccordionChange"监听事件。handleAccordionChange函数会接收到最新的展开状态值。 - 重要:在
handleAccordionChange中,你必须手动更新currentActiveItem.value = newValue,否则手风琴的展开状态将不会在 UI 上反映出来,因为它不再是自动双向绑定。 - 你可以在
handleAccordionChange函数中加入任何你需要的自定义逻辑。
Theme
export default defineAppConfig({
ui: {
accordion: {
slots: {
root: 'w-full',
item: 'border-b border-default last:border-b-0',
header: 'flex',
trigger: 'group flex-1 flex items-center gap-1.5 font-medium text-sm py-3.5 focus-visible:outline-primary min-w-0',
content: 'data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none',
body: 'text-sm pb-3.5',
leadingIcon: 'shrink-0 size-5',
trailingIcon: 'shrink-0 size-5 ms-auto group-data-[state=open]:rotate-180 transition-transform duration-200',
label: 'text-start break-words'
},
variants: {
disabled: {
true: {
trigger: 'cursor-not-allowed opacity-75'
}
}
}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
accordion: {
slots: {
root: 'w-full',
item: 'border-b border-default last:border-b-0',
header: 'flex',
trigger: 'group flex-1 flex items-center gap-1.5 font-medium text-sm py-3.5 focus-visible:outline-primary min-w-0',
content: 'data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none',
body: 'text-sm pb-3.5',
leadingIcon: 'shrink-0 size-5',
trailingIcon: 'shrink-0 size-5 ms-auto group-data-[state=open]:rotate-180 transition-transform duration-200',
label: 'text-start break-words'
},
variants: {
disabled: {
true: {
trigger: 'cursor-not-allowed opacity-75'
}
}
}
}
}
})
]
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'
export default defineConfig({
plugins: [
vue(),
uiPro({
ui: {
accordion: {
slots: {
root: 'w-full',
item: 'border-b border-default last:border-b-0',
header: 'flex',
trigger: 'group flex-1 flex items-center gap-1.5 font-medium text-sm py-3.5 focus-visible:outline-primary min-w-0',
content: 'data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none',
body: 'text-sm pb-3.5',
leadingIcon: 'shrink-0 size-5',
trailingIcon: 'shrink-0 size-5 ms-auto group-data-[state=open]:rotate-180 transition-transform duration-200',
label: 'text-start break-words'
},
variants: {
disabled: {
true: {
trigger: 'cursor-not-allowed opacity-75'
}
}
}
}
}
})
]
})
disabled="true" 属性时,该手风琴项的 “标题/点击区域”(即 trigger)就会自动拥有一个 “禁止点击” 的鼠标游标和 75% 的不透明度。在 Nuxt UI 中,
app.config.ts 文件允许你对所有组件进行全局默认样式的定制。而 variants 字段是其中非常重要的一个部分,它专门用来定义组件在不同状态或不同属性值下所展现的样式 “变体”。
你可以把它想象成:当组件的某个属性发生变化时,它的外观也会随之改变,而 variants 就是预先定义这些变化规则的地方。
variants 的配置方式 variants 字段在 app.config.ts 中用于定义基于组件 props 值的条件样式。它的结构通常是:variants: {
// `propName` 是组件的 prop 名称
propName: {
// `propValue` 是 prop 的一个可能值
propValue: {
// `componentPart` 是组件内部的一个部分(比如 `root`, `title`, `description`, `icon` 等)
componentPart: 'tailwind-css-classes'
},
// ... 其他 propValue
},
// ... 其他 propName
}
compoundVariants 的配置方式,就是:当一个或多个特定的 props 组合出现时,才应用某些额外的样式。compoundVariants 的语法结构它通常是 variants 同级的一个数组,每个数组项是一个对象:// app.config.ts 或组件的 theme 定义中
export default defineAppConfig({
ui: {
ComponentName: {
// ... 其他 slots 和 variants 配置
compoundVariants: [
{
// 第一个对象定义了触发这个复合变体的 prop 组合
// 这些键/值对必须与组件的 props 名称及其值匹配
propName1: 'propValueA',
propName2: 'propValueB',
// ... 更多 prop 组合条件
class: {
// `componentPart` 是组件内部的一个部分(比如 `root`, `title`, `description`, `icon` 等)
componentPart: 'tailwind-css-classes'
} // 当所有条件都满足时应用的类
},
{
// 第二个复合变体规则
propNameX: 'propValueY',
propNameZ: true,
class: {
// `componentPart` 是组件内部的一个部分(比如 `root`, `title`, `description`, `icon` 等)
componentPart: 'tailwind-css-classes'
}
}
// ... 更多复合变体
]
}
}
})
defaultVariants 的作用
defaultVariants 主要用于:- 设置组件的默认样式变体:它指定了在没有显式传递某些 prop 时,组件应该使用哪种颜色、变体、尺寸等。
- 减少重复代码:避免在每次使用组件时都手动设置那些你希望大多数情况下都是默认的 prop。
- 提供一致的基准外观:确保组件在被使用时,即使没有传递任何 prop,也能有一个合理的、符合设计规范的初始状态。
defaultVariants 的语法结构它通常是 variants 同级的一个对象,键是 prop 名称,值是该 prop 的默认值。// app.config.ts 或组件的 theme 定义中
export default defineAppConfig({
ui: {
ComponentName: {
// ... slots 和 variants 配置
defaultVariants: {
propName1: 'defaultValue1',
propName2: 'defaultValue2',
// ... 更多 prop 的默认值
}
}
}
})
defaultVariants 如何与 props 和 variants 协作defaultVariants 的优先级通常是这样的(从低到高):- 组件内置主题的
defaultVariants: 组件本身定义的最基础的默认值。 app.config.ts中的defaultVariants: 你在全局配置中覆盖或扩展的默认值。- 组件实例上直接传递的
prop: 这是最高优先级,会覆盖所有默认值。