使用
该 InputMenu
组件默认渲染一个 输入框 组件,并基于 ui.input
预设。您可以使用大多数 输入框
属性来配置显示,例如 颜色、变体、大小、占位符、图标、禁用 等。
您可以像 输入框
组件一样使用 ui
属性来覆盖默认配置。该 uiMenu
属性可用于覆盖默认菜单配置。
将字符串或对象的数组传递给 options
属性以在菜单中显示。
<script setup lang="ts">
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" />
</template>
对象
您可以将对象的数组传递给 options
,并根据整个对象进行比较或使用 by
属性根据特定键进行比较。您可以通过 option-attribute
属性配置用于显示标签的字段,该属性默认为 label
。此外,您可以使用点表示法(例如,user.name
)来访问嵌套对象属性。
<script setup lang="ts">
import type { Avatar } from '#ui/types'
const people = [{
id: 'benjamincanac',
label: 'benjamincanac',
href: 'https://github.com/benjamincanac',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/739984?v=4' }
}, {
id: 'Atinux',
label: 'Atinux',
href: 'https://github.com/Atinux',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/904724?v=4' }
}, {
id: 'smarroufin',
label: 'smarroufin',
href: 'https://github.com/smarroufin',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/7547335?v=4' }
}, {
id: 'nobody',
label: 'Nobody',
icon: 'i-heroicons-user-circle'
}]
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people">
<template #leading>
<UIcon v-if="selected.icon" :name="(selected.icon as string)" class="w-5 h-5" />
<UAvatar v-else-if="selected.avatar" v-bind="(selected.avatar as Avatar)" size="2xs" />
</template>
</UInputMenu>
</template>
使用包含属性名称数组的 search-attributes
属性来搜索每个选项对象。嵌套属性可以使用 dot.notation
访问。当属性值为数组或对象时,它们会转换为字符串,以便可以在其中搜索。
<script setup lang="ts">
const options = [
{ id: 1, name: 'Wade Cooper', colors: ['red', 'yellow'] },
{ id: 2, name: 'Arlene Mccoy', colors: ['blue', 'yellow'] },
{ id: 3, name: 'Devon Webb', colors: ['green', 'blue'] },
{ id: 4, name: 'Tom Cook', colors: ['blue', 'red'] },
{ id: 5, name: 'Tanya Fox', colors: ['green', 'red'] },
{ id: 5, name: 'Hellen Schmidt', colors: ['green', 'yellow'] }
]
const selected = ref(options[1])
</script>
<template>
<UInputMenu
v-model="selected"
:options="options"
placeholder="Select a person"
by="id"
option-attribute="name"
:search-attributes="['name', 'colors']"
>
<template #option="{ option: person }">
<span v-for="color in person.colors" :key="color.id" class="h-2 w-2 rounded-full" :class="`bg-${color}-500 dark:bg-${color}-400`" />
<span class="truncate">{{ person.name }}</span>
</template>
</UInputMenu>
</template>
如果您只想选择单个对象属性而不是整个对象作为值,可以设置 value-attribute
属性。此属性默认为 null
。
<script setup lang="ts">
const people = [{
id: 1,
name: 'Wade Cooper'
}, {
id: 2,
name: 'Arlene Mccoy'
}, {
id: 3,
name: 'Devon Webb'
}, {
id: 4,
name: 'Tom Cook'
}]
const selected = ref(people[0].id)
</script>
<template>
<UInputMenu
v-model="selected"
:options="people"
value-attribute="id"
option-attribute="name"
/>
</template>
图标
该 InputMenu
在右侧有一个按钮用于切换菜单。使用 trailing-icon
属性设置不同的图标或在 ui.inputMenu.default.trailingIcon
中全局更改它。默认为 i-heroicons-chevron-down-20-solid
。
<template>
<UInputMenu
trailing-icon="i-heroicons-chevron-up-down-20-solid"
class="w-full lg:w-48"
placeholder="Select a person"
:options="['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']"
/>
</template>
使用 selected-icon
属性设置不同的图标或在 ui.inputMenu.default.selectedIcon
中全局更改它。默认为 i-heroicons-check-20-solid
。
<template>
<UInputMenu
selected-icon="i-heroicons-hand-thumb-up-solid"
class="w-full lg:w-48"
placeholder="Select a person"
:options="['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']"
/>
</template>
可搜索
属性
使用包含属性名称数组的 search-attributes
属性来搜索每个选项对象。嵌套属性可以使用 dot.notation
访问。当属性值为数组或对象时,它们会转换为字符串,以便可以在其中搜索。
<script setup lang="ts">
const options = [
{ id: 1, name: 'Wade Cooper', colors: ['red', 'yellow'] },
{ id: 2, name: 'Arlene Mccoy', colors: ['blue', 'yellow'] },
{ id: 3, name: 'Devon Webb', colors: ['green', 'blue'] },
{ id: 4, name: 'Tom Cook', colors: ['blue', 'red'] },
{ id: 5, name: 'Tanya Fox', colors: ['green', 'red'] },
{ id: 5, name: 'Hellen Schmidt', colors: ['green', 'yellow'] }
]
const selected = ref(options[1])
</script>
<template>
<UInputMenu
v-model="selected"
:options="options"
placeholder="Select a person"
by="id"
option-attribute="name"
:search-attributes="['name', 'colors']"
>
<template #option="{ option: person }">
<span v-for="color in person.colors" :key="color.id" class="h-2 w-2 rounded-full" :class="`bg-${color}-500 dark:bg-${color}-400`" />
<span class="truncate">{{ person.name }}</span>
</template>
</UInputMenu>
</template>
控制查询
使用 v-model:query
控制搜索查询。
<script setup lang="ts">
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref()
const query = ref('Wade')
</script>
<template>
<UInputMenu
v-model="selected"
v-model:query="query"
:options="people"
placeholder="Select a person"
/>
</template>
异步搜索
将函数传递给 search
属性以自定义搜索行为并根据您的需求过滤选项。该函数将接收查询作为其第一个参数,并应返回一个数组。
使用 debounce
属性调整函数的延迟。
使用 searchLazy
属性控制数据请求的即时性。
<script setup lang="ts">
const loading = ref(false)
const selected = ref()
async function search(q: string) {
loading.value = true
const users: any[] = await $fetch('https://jsonplaceholder.typicode.com/users', { params: { q } })
loading.value = false
return users
}
</script>
<template>
<UInputMenu
v-model="selected"
:search="search"
:loading="loading"
placeholder="Search for a user..."
option-attribute="name"
trailing
by="id"
/>
</template>
弹出框
使用 popper
属性自定义弹出框实例。
箭头
<script setup lang="ts">
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" :popper="{ arrow: true }" />
</template>
位置
<script setup lang="ts">
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" :popper="{ placement: 'right-start' }" />
</template>
偏移量
<script setup lang="ts">
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" :popper="{ offsetDistance: 0 }" />
</template>
插槽
option
使用 #option
插槽自定义选项内容。您将可以在插槽作用域中访问 option
、active
和 selected
属性。
<script setup lang="ts">
const people = [
{ name: 'Wade Cooper', online: true },
{ name: 'Arlene Mccoy', online: false },
{ name: 'Devon Webb', online: false },
{ name: 'Tom Cook', online: true },
{ name: 'Tanya Fox', online: false },
{ name: 'Hellen Schmidt', online: true },
{ name: 'Caroline Schultz', online: true },
{ name: 'Mason Heaney', online: false },
{ name: 'Claudie Smitham', online: true },
{ name: 'Emil Schaefer', online: false }
]
const selected = ref(people[3])
</script>
<template>
<UInputMenu v-model="selected" :options="people" option-attribute="name">
<template #option="{ option: person }">
<span :class="[person.online ? 'bg-green-400' : 'bg-gray-200', 'inline-block h-2 w-2 flex-shrink-0 rounded-full']" aria-hidden="true" />
<span class="truncate">{{ person.name }}</span>
</template>
</UInputMenu>
</template>
option-empty
使用 #option-empty
插槽自定义当 searchable
属性为 true
且没有选项时显示的内容。您将可以在插槽作用域中访问 query
属性。
您也可以通过 ui.inputMenu.default.optionEmpty.label
配置全局设置。令牌 {query}
将被 query
属性替换。默认为 未找到 "{query}" 的结果。
。
<script setup lang="ts">
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" searchable>
<template #option-empty="{ query }">
<q>{{ query }}</q> not found
</template>
</UInputMenu>
</template>
empty
使用 #empty
插槽自定义没有选项时显示的内容。默认为 没有选项。
。
您也可以通过 ui.inputMenu.default.empty.label
配置全局设置。默认为 没有选项。
。
<script setup lang="ts">
const people = []
const selected = ref()
</script>
<template>
<UInputMenu v-model="selected" :options="people">
<template #empty>
No people
</template>
</UInputMenu>
</template>
属性
null
null
"md"
"2xs"
"xs"
"sm"
"lg"
"xl"
undefined
config.default.color
null
{}
null
""
null
[]
config.default.variant
"outline"
"none"
null
config.default.loadingIcon
null
configMenu.default.trailingIcon
undefined
{}
null
configMenu.default.selectedIcon
"label"
null
null
200
{}
false
false
false
false
false
false
true
false
配置
ui
属性来覆盖输入配置,使用 uiMenu
属性来覆盖菜单配置。{
container: 'z-20 group',
trigger: 'flex items-center w-full',
width: 'w-full',
height: 'max-h-60',
base: 'relative focus:outline-none overflow-y-auto scroll-py-1',
background: 'bg-white dark:bg-gray-800',
shadow: 'shadow-lg',
rounded: 'rounded-md',
padding: 'p-1',
ring: 'ring-1 ring-gray-200 dark:ring-gray-700',
empty: 'text-sm text-gray-400 dark:text-gray-500 px-2 py-1.5',
option: {
base: 'cursor-default select-none relative flex items-center justify-between gap-1',
rounded: 'rounded-md',
padding: 'px-1.5 py-1.5',
size: 'text-sm',
color: 'text-gray-900 dark:text-white',
container: 'flex items-center gap-1.5 min-w-0',
active: 'bg-gray-100 dark:bg-gray-900',
inactive: '',
selected: 'pe-7',
disabled: 'cursor-not-allowed opacity-50',
empty: 'text-sm text-gray-400 dark:text-gray-500 px-2 py-1.5',
icon: {
base: 'flex-shrink-0 h-5 w-5',
active: 'text-gray-900 dark:text-white',
inactive: 'text-gray-400 dark:text-gray-500'
},
selectedIcon: {
wrapper: 'absolute inset-y-0 end-0 flex items-center',
padding: 'pe-2',
base: 'h-5 w-5 text-gray-900 dark:text-white flex-shrink-0'
},
avatar: {
base: 'flex-shrink-0',
size: '2xs'
},
chip: {
base: 'flex-shrink-0 w-2 h-2 mx-1 rounded-full'
}
},
transition: {
leaveActiveClass: 'transition ease-in duration-100',
leaveFromClass: 'opacity-100',
leaveToClass: 'opacity-0'
},
popper: {
placement: 'bottom-end'
},
default: {
selectedIcon: 'i-heroicons-check-20-solid',
trailingIcon: 'i-heroicons-chevron-down-20-solid',
empty: {
label: 'No options.'
},
optionEmpty: {
label: 'No results for "{query}".'
}
},
arrow: {
base: 'invisible before:visible before:block before:rotate-45 before:z-[-1] before:w-2 before:h-2',
ring: 'before:ring-1 before:ring-gray-200 dark:before:ring-gray-700',
rounded: 'before:rounded-sm',
background: 'before:bg-white dark:before:bg-gray-700',
shadow: 'before:shadow',
placement: "group-data-[popper-placement*='right']:-left-1 group-data-[popper-placement*='left']:-right-1 group-data-[popper-placement*='top']:-bottom-1 group-data-[popper-placement*='bottom']:-top-1"
}
}