#Select 选择器
显示一个选项列表供用户选择——由按钮触发。复制了 shadcn-vue Select 组件的核心能力,支持单选、多选、搜索、分组和其他功能。基于 BrConfigProvider 进行全局主题配置。
#组件特性
- ✅ 单选和多选:支持单选和多选模式。
- 🔍 搜索支持:支持本地和远程搜索过滤。
- 📦 分组支持:通过
BrSelectGroup支持选项分组。 - ❌ 可清除:支持
clearable属性清除选择。 - 📏 多种尺寸:支持
sm、md、lg尺寸规格。 - ⚠️ 错误状态:支持
error属性显示错误状态。 - 🎨 主题定制:基于
BrConfigProvider支持全局主题配置和 TailwindCSS 局部覆盖。
#基础用法
最基本的单选模式,支持自定义占位符。
<script setup lang="ts">
import { BrSelect } from '@breezeui/vue'
import { ref } from 'vue'
const value = ref('apple')
const options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
{ label: 'Blueberry', value: 'blueberry' },
{ label: 'Grapes', value: 'grapes' },
{ label: 'Pineapple', value: 'pineapple' },
]
</script>
<template>
<div class="flex flex-col gap-4 w-[280px]">
<BrSelect
v-model="value"
:options="options"
placeholder="Select a fruit"
/>
<div class="text-sm text-muted-foreground">
Selected: {{ value }}
</div>
</div>
</template>#分组
使用 group 字段将选项分组显示。
<script setup lang="ts">
import { BrSelect } from '@breezeui/vue'
import { ref } from 'vue'
const value = ref('')
const options = [
{ label: 'Apple', value: 'apple', group: 'Fruits' },
{ label: 'Banana', value: 'banana', group: 'Fruits' },
{ label: 'Blueberry', value: 'blueberry', group: 'Fruits' },
{ label: 'Carrot', value: 'carrot', group: 'Vegetables' },
{ label: 'Potato', value: 'potato', group: 'Vegetables' },
{ label: 'Broccoli', value: 'broccoli', group: 'Vegetables' },
{ label: 'Beef', value: 'beef', group: 'Meat' },
{ label: 'Chicken', value: 'chicken', group: 'Meat' },
]
</script>
<template>
<div class="w-[280px]">
<BrSelect
v-model="value"
:options="options"
placeholder="Select food"
/>
</div>
</template>#远程搜索
启用 filterable 属性并监听 search 事件以实现远程搜索。支持 loading 状态。
<script setup lang="ts">
import { BrSelect } from '@breezeui/vue'
import { ref, watch } from 'vue'
const value = ref('')
const loading = ref(false)
const options = ref<{ label: string; value: string }[]>([])
// Simulate remote search
const handleSearch = (query: string) => {
if (!query) {
options.value = []
return
}
loading.value = true
// Mock API call
setTimeout(() => {
options.value = [
{ label: query + ' Option 1', value: query + '-1' },
{ label: query + ' Option 2', value: query + '-2' },
{ label: query + ' Option 3', value: query + '-3' },
]
loading.value = false
}, 1000)
}
</script>
<template>
<div class="w-[280px]">
<BrSelect
v-model="value"
:options="options"
filterable
:loading="loading"
placeholder="Type to search..."
empty-text="No results found."
@search="handleSearch"
/>
<div class="mt-4 text-sm text-muted-foreground">
Current Value: {{ value }}
</div>
</div>
</template>#多选与可清除
启用 multiple 属性以支持多选,启用 clearable 以支持一键清除。
<script setup lang="ts">
import { BrSelect } from '@breezeui/vue'
import { ref } from 'vue'
const value = ref(['react', 'vue'])
const options = [
{ label: 'Vue', value: 'vue' },
{ label: 'React', value: 'react' },
{ label: 'Angular', value: 'angular' },
{ label: 'Svelte', value: 'svelte' },
{ label: 'Solid', value: 'solid' },
]
</script>
<template>
<div class="flex flex-col gap-4 w-[350px]">
<BrSelect
v-model="value"
:options="options"
multiple
clearable
placeholder="Select frameworks"
/>
<div class="text-sm text-muted-foreground">
Selected: {{ value }}
</div>
</div>
</template>#尺寸
支持 default, sm, lg 尺寸。
<script setup lang="ts">
import { BrSelect } from '@breezeui/vue'
import { ref } from 'vue'
const value = ref('apple')
const options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
]
</script>
<template>
<div class="flex flex-col gap-4 w-full max-w-sm">
<div class="grid gap-2">
<label class="text-sm font-medium">Extra Small Size (xs)</label>
<BrSelect v-model="value" :options="options" size="xs" />
</div>
<div class="grid gap-2">
<label class="text-sm font-medium">Small Size (sm)</label>
<BrSelect v-model="value" :options="options" size="sm" />
</div>
<div class="grid gap-2">
<label class="text-sm font-medium">Default Size</label>
<BrSelect v-model="value" :options="options" />
</div>
<div class="grid gap-2">
<label class="text-sm font-medium">Medium Size (md)</label>
<BrSelect v-model="value" :options="options" size="md" />
</div>
<div class="grid gap-2">
<label class="text-sm font-medium">Large Size (lg)</label>
<BrSelect v-model="value" :options="options" size="lg" />
</div>
<div class="grid gap-2">
<label class="text-sm font-medium">Extra Large Size (xl)</label>
<BrSelect v-model="value" :options="options" size="xl" />
</div>
<div class="grid gap-2">
<label class="text-sm font-medium">2X Large Size (2xl)</label>
<BrSelect v-model="value" :options="options" size="2xl" />
</div>
</div>
</template>#状态
支持 error 状态。
<script setup lang="ts">
import { BrSelect } from '@breezeui/vue'
import { ref } from 'vue'
const value = ref('apple')
const options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
]
</script>
<template>
<div class="flex flex-col gap-4 w-full max-w-sm">
<div class="grid gap-2">
<label class="text-sm font-medium">Error State</label>
<BrSelect v-model="value" :options="options" error />
</div>
</div>
</template>#主题定制
BrSelect 组件完全遵循 BrConfigProvider 的主题规范。
#全局配置与局部覆盖
- 全局配置:通过
BrConfigProvider的theme属性配置全局颜色,Select 组件将自动适配。 - 局部覆盖:你可以使用 Tailwind CSS 类名直接覆盖样式。
<script setup lang="ts">
import { BrSelect, BrConfigProvider } from '@breezeui/vue'
import { ref } from 'vue'
const value = ref('light')
const options = [
{ label: 'Light Mode', value: 'light' },
{ label: 'Dark Mode', value: 'dark' },
{ label: 'System', value: 'system' },
]
// Custom theme configuration
const customTheme = {
background: '222.2 84% 4.9%',
foreground: '210 40% 98%',
popover: '222.2 84% 4.9%',
popoverForeground: '210 40% 98%',
primary: '210 40% 98%',
primaryForeground: '222.2 47.4% 11.2%',
border: '217.2 32.6% 17.5%',
input: '217.2 32.6% 17.5%',
ring: '212.7 26.8% 83.9%',
}
</script>
<template>
<div class="space-y-8">
<!-- Default Theme -->
<div class="space-y-2">
<h3 class="text-sm font-medium">Default Theme</h3>
<div class="w-[280px]">
<BrSelect v-model="value" :options="options" />
</div>
</div>
<!-- Custom Dark Theme via ConfigProvider -->
<div class="space-y-2">
<h3 class="text-sm font-medium">Custom Dark Theme (via ConfigProvider)</h3>
<BrConfigProvider :theme="customTheme" class="p-6 rounded-lg border bg-background text-foreground">
<div class="w-[280px]">
<BrSelect v-model="value" :options="options" />
</div>
</BrConfigProvider>
</div>
</div>
</template>#API
#Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| modelValue | string | number | (string | number)[] | - | 绑定值 |
| options | (string | number | SelectOption)[] | [] | 选项数据 |
| placeholder | string | 'Select an option' | 占位符 |
| disabled | boolean | false | 是否禁用 |
| clearable | boolean | false | 是否可清除 |
| filterable | boolean | false | 是否可搜索 |
| multiple | boolean | false | 是否多选 |
| loading | boolean | false | 是否加载中(用于远程搜索) |
| emptyText | string | 'No options found.' | 当未找到选项时显示的文本 |
| size | 'default' | 'sm' | 'lg' | 'default' | 尺寸 |
| error | boolean | false | 是否处于错误状态 |
#SelectOption 类型
interface SelectOption {
label: string
value: string | number
disabled?: boolean
group?: string
}#Events
| 名称 | 说明 | 参数 |
|---|---|---|
| update:modelValue | 当绑定值变化时触发 | value: string | number | (string | number)[] |
| change | 当选中值变化时触发 | value: string | number | (string | number)[] |
| clear | 当点击清除按钮时触发 | - |
| search | 当搜索输入变化时触发 | query: string |