自动完成
v-autocomplete
组件提供简单灵活的输入提示功能。当搜索大量数据甚至从 API 中动态请求信息时是十分有用的。
用例
自动完成组件扩展了v-select
并为其增加了过滤项目的能力。
在为 items 属性使用对象时,您必须将 item-text 和 item-value 与对象上的现有属性关联。这些值默认为 text 和 value,可以更改。
menu-props 的 auto 属性只支持默认输入样式。
浏览器自动完成默认设置为关闭,可能因浏览器而异,可能会被忽略。MDN
API
从下面选择您想要的组件,并查看可用的属性、插槽、事件和函数。
示例
下面是一些简单到复杂的例子。
搜索 API
轻松绑定动态数据并创造独特的体验。v-autocomplete
的扩展的支持列表使得对输入的各个方面进行调优变得很容易。
template script
<template>
<v-card
color="red lighten-2"
dark
>
<v-card-title class="headline red lighten-3">
Search for Public APIs
</v-card-title>
<v-card-text>
Explore hundreds of free API's ready for consumption! For more information visit
<a
class="grey--text text--lighten-3"
href="https://github.com/toddmotto/public-apis"
target="_blank"
>the Github repository</a>.
</v-card-text>
<v-card-text>
<v-autocomplete
v-model="model"
:items="items"
:loading="isLoading"
:search-input.sync="search"
color="white"
hide-no-data
hide-selected
item-text="Description"
item-value="API"
label="Public APIs"
placeholder="Start typing to Search"
prepend-icon="mdi-database-search"
return-object
></v-autocomplete>
</v-card-text>
<v-divider></v-divider>
<v-expand-transition>
<v-list v-if="model" class="red lighten-3">
<v-list-item
v-for="(field, i) in fields"
:key="i"
>
<v-list-item-content>
<v-list-item-title v-text="field.value"></v-list-item-title>
<v-list-item-subtitle v-text="field.key"></v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
</v-expand-transition>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
:disabled="!model"
color="grey darken-3"
@click="model = null"
>
Clear
<v-icon right>mdi-close-circle</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
data: () => ({
descriptionLimit: 60,
entries: [],
isLoading: false,
model: null,
search: null,
}),
computed: {
fields () {
if (!this.model) return []
return Object.keys(this.model).map(key => {
return {
key,
value: this.model[key] || 'n/a',
}
})
},
items () {
return this.entries.map(entry => {
const Description = entry.Description.length > this.descriptionLimit
? entry.Description.slice(0, this.descriptionLimit) + '...'
: entry.Description
return Object.assign({}, entry, { Description })
})
},
},
watch: {
search (val) {
// Items have already been loaded
if (this.items.length > 0) return
// Items have already been requested
if (this.isLoading) return
this.isLoading = true
// Lazily load input items
fetch('https://api.publicapis.org/entries')
.then(res => res.json())
.then(res => {
const { count, entries } = res
this.count = count
this.entries = entries
})
.catch(err => {
console.log(err)
})
.finally(() => (this.isLoading = false))
},
},
}
</script>
自动完成时的自定义过滤器
propfilter
可以用来过滤每个项目,并带有自定义逻辑。在这个例子中,我们按名称过滤项目
template script
<template>
<v-card
class="overflow-hidden"
color="purple lighten-1"
dark
>
<v-toolbar
flat
color="purple"
>
<v-icon>mdi-account</v-icon>
<v-toolbar-title class="font-weight-light">User Profile</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn
color="purple darken-3"
fab
small
@click="isEditing = !isEditing"
>
<v-icon v-if="isEditing">mdi-close</v-icon>
<v-icon v-else>mdi-pencil</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<v-text-field
:disabled="!isEditing"
color="white"
label="Name"
></v-text-field>
<v-autocomplete
:disabled="!isEditing"
:items="states"
:filter="customFilter"
color="white"
item-text="name"
label="State"
></v-autocomplete>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
:disabled="!isEditing"
color="success"
@click="save"
>
Save
</v-btn>
</v-card-actions>
<v-snackbar
v-model="hasSaved"
:timeout="2000"
absolute
bottom
left
>
Your profile has been updated
</v-snackbar>
</v-card>
</template>
<script>
export default {
data () {
return {
hasSaved: false,
isEditing: null,
model: null,
states: [
{ name: 'Florida', abbr: 'FL', id: 1 },
{ name: 'Georgia', abbr: 'GA', id: 2 },
{ name: 'Nebraska', abbr: 'NE', id: 3 },
{ name: 'California', abbr: 'CA', id: 4 },
{ name: 'New York', abbr: 'NY', id: 5 },
],
}
},
methods: {
customFilter (item, queryText, itemText) {
const textOne = item.name.toLowerCase()
const textTwo = item.abbr.toLowerCase()
const searchText = queryText.toLowerCase()
return textOne.indexOf(searchText) > -1 ||
textTwo.indexOf(searchText) > -1
},
save () {
this.isEditing = !this.isEditing
this.hasSaved = true
},
},
}
</script>
密集
您可以使用 dense
属性来降低自动完成高度和列表项的最大高度。
template script
<template>
<v-card>
<v-container fluid>
<v-row
align="center"
>
<v-col cols="12">
<v-autocomplete
v-model="values"
:items="items"
outlined
dense
chips
small-chips
label="Outlined"
multiple
></v-autocomplete>
</v-col>
<v-col cols="12">
<v-autocomplete
v-model="values"
:items="items"
dense
chips
small-chips
label="Solo"
multiple
solo
></v-autocomplete>
</v-col>
<v-col cols="12">
<v-autocomplete
v-model="value"
:items="items"
dense
filled
label="Filled"
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-card>
</template>
<script>
export default {
data: () => ({
items: ['foo', 'bar', 'fizz', 'buzz'],
values: ['foo', 'bar'],
value: null,
}),
}
</script>
插槽
利用插槽的强大功能,您可以自定义选择的可视输出。在本例中,我们为纸片和列表项添加了一个配置文件图片。
template script
<template>
<v-card
color="blue-grey darken-1"
dark
:loading="isUpdating"
>
<template v-slot:progress>
<v-progress-linear
absolute
color="green lighten-3"
height="4"
indeterminate
></v-progress-linear>
</template>
<v-img
height="200"
src="https://cdn.vuetifyjs.com/images/cards/dark-beach.jpg"
>
<v-row>
<v-col
class="text-right"
cols="12"
>
<v-menu
bottom
left
transition="slide-y-transition"
>
<template v-slot:activator="{ on }">
<v-btn
icon
v-on="on"
>
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item @click="isUpdating = true">
<v-list-item-action>
<v-icon>mdi-settings</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>Update</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</v-col>
<v-row
class="pa-4"
align="center"
justify="center"
>
<v-col class="text-center">
<h3 class="headline">{{ name }}</h3>
<span class="grey--text text--lighten-1">{{ title }}</span>
</v-col>
</v-row>
</v-row>
</v-img>
<v-form>
<v-container>
<v-row>
<v-col
cols="12"
md="6"
>
<v-text-field
v-model="name"
:disabled="isUpdating"
filled
color="blue-grey lighten-2"
label="Name"
></v-text-field>
</v-col>
<v-col
cols="12"
md="6"
>
<v-text-field
v-model="title"
:disabled="isUpdating"
filled
color="blue-grey lighten-2"
label="Title"
></v-text-field>
</v-col>
<v-col cols="12">
<v-autocomplete
v-model="friends"
:disabled="isUpdating"
:items="people"
filled
chips
color="blue-grey lighten-2"
label="Select"
item-text="name"
item-value="name"
multiple
>
<template v-slot:selection="data">
<v-chip
v-bind="data.attrs"
:input-value="data.selected"
close
@click="data.select"
@click:close="remove(data.item)"
>
<v-avatar left>
<v-img :src="data.item.avatar"></v-img>
</v-avatar>
{{ data.item.name }}
</v-chip>
</template>
<template v-slot:item="data">
<template v-if="typeof data.item !== 'object'">
<v-list-item-content v-text="data.item"></v-list-item-content>
</template>
<template v-else>
<v-list-item-avatar>
<img :src="data.item.avatar">
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-html="data.item.name"></v-list-item-title>
<v-list-item-subtitle v-html="data.item.group"></v-list-item-subtitle>
</v-list-item-content>
</template>
</template>
</v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-form>
<v-divider></v-divider>
<v-card-actions>
<v-switch
v-model="autoUpdate"
:disabled="isUpdating"
class="mt-0"
color="green lighten-2"
hide-details
label="Auto Update"
></v-switch>
<v-spacer></v-spacer>
<v-btn
:disabled="autoUpdate"
:loading="isUpdating"
color="blue-grey darken-3"
depressed
@click="isUpdating = true"
>
<v-icon left>mdi-update</v-icon>
Update Now
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
data () {
const srcs = {
1: 'https://cdn.vuetifyjs.com/images/lists/1.jpg',
2: 'https://cdn.vuetifyjs.com/images/lists/2.jpg',
3: 'https://cdn.vuetifyjs.com/images/lists/3.jpg',
4: 'https://cdn.vuetifyjs.com/images/lists/4.jpg',
5: 'https://cdn.vuetifyjs.com/images/lists/5.jpg',
}
return {
autoUpdate: true,
friends: ['Sandra Adams', 'Britta Holt'],
isUpdating: false,
name: 'Midnight Crew',
people: [
{ header: 'Group 1' },
{ name: 'Sandra Adams', group: 'Group 1', avatar: srcs[1] },
{ name: 'Ali Connors', group: 'Group 1', avatar: srcs[2] },
{ name: 'Trevor Hansen', group: 'Group 1', avatar: srcs[3] },
{ name: 'Tucker Smith', group: 'Group 1', avatar: srcs[2] },
{ divider: true },
{ header: 'Group 2' },
{ name: 'Britta Holt', group: 'Group 2', avatar: srcs[4] },
{ name: 'Jane Smith ', group: 'Group 2', avatar: srcs[5] },
{ name: 'John Smith', group: 'Group 2', avatar: srcs[1] },
{ name: 'Sandra Williams', group: 'Group 2', avatar: srcs[3] },
],
title: 'The summer breeze',
}
},
watch: {
isUpdating (val) {
if (val) {
setTimeout(() => (this.isUpdating = false), 3000)
}
},
},
methods: {
remove (item) {
const index = this.friends.indexOf(item.name)
if (index >= 0) this.friends.splice(index, 1)
},
},
}
</script>
Alpha Theme
Complete theme experience including enhanced Vue CLI, full documentation, 5 custom components and much more!
ads by Vuetify
](https://store.vuetifyjs.com/product/alpha-theme?ref=vuetifyjs.com)
异步项目
有时您需要根据搜索查询从外部加载数据。 使用 autocomplete
属性时,请使用带有 .sync 修饰符的 search-input
属性。 我们还利用了新的 cache-items
属性。 这将保留已传递给 items
属性的所有物品的唯一列表,并且在使用异步属性和 multiple 属性时是 REQUIRED 的。
template script
<template>
<v-toolbar
dark
color="teal"
>
<v-toolbar-title>State selection</v-toolbar-title>
<v-autocomplete
v-model="select"
:loading="loading"
:items="items"
:search-input.sync="search"
cache-items
class="mx-4"
flat
hide-no-data
hide-details
label="What state are you from?"
solo-inverted
></v-autocomplete>
<v-btn icon>
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</v-toolbar>
</template>
<script>
export default {
data () {
return {
loading: false,
items: [],
search: null,
select: null,
states: [
'Alabama',
'Alaska',
'American Samoa',
'Arizona',
'Arkansas',
'California',
'Colorado',
'Connecticut',
'Delaware',
'District of Columbia',
'Federated States of Micronesia',
'Florida',
'Georgia',
'Guam',
'Hawaii',
'Idaho',
'Illinois',
'Indiana',
'Iowa',
'Kansas',
'Kentucky',
'Louisiana',
'Maine',
'Marshall Islands',
'Maryland',
'Massachusetts',
'Michigan',
'Minnesota',
'Mississippi',
'Missouri',
'Montana',
'Nebraska',
'Nevada',
'New Hampshire',
'New Jersey',
'New Mexico',
'New York',
'North Carolina',
'North Dakota',
'Northern Mariana Islands',
'Ohio',
'Oklahoma',
'Oregon',
'Palau',
'Pennsylvania',
'Puerto Rico',
'Rhode Island',
'South Carolina',
'South Dakota',
'Tennessee',
'Texas',
'Utah',
'Vermont',
'Virgin Island',
'Virginia',
'Washington',
'West Virginia',
'Wisconsin',
'Wyoming',
],
}
},
watch: {
search (val) {
val && val !== this.select && this.querySelections(val)
},
},
methods: {
querySelections (v) {
this.loading = true
// Simulated ajax query
setTimeout(() => {
this.items = this.states.filter(e => {
return (e || '').toLowerCase().indexOf((v || '').toLowerCase()) > -1
})
this.loading = false
}, 500)
},
},
}
</script>
高级插槽
v-autocomplete
组件非常灵活,几乎可以适应任何用例。 为 no-data, item 和 selection 插槽创建自定义显示,以提供独特的用户体验。 使用 slots 可使您轻松自定义应用程序所需的外观。
template script
<template>
<v-toolbar color="orange accent-1">
<v-app-bar-nav-icon class="hidden-sm-and-down"></v-app-bar-nav-icon>
<v-toolbar-title class="title mr-6 hidden-sm-and-down">Cryptocurrency</v-toolbar-title>
<v-autocomplete
v-model="model"
:items="items"
:loading="isLoading"
:search-input.sync="search"
chips
clearable
hide-details
hide-selected
item-text="name"
item-value="symbol"
label="Search for a coin..."
solo
>
<template v-slot:no-data>
<v-list-item>
<v-list-item-title>
Search for your favorite
<strong>Cryptocurrency</strong>
</v-list-item-title>
</v-list-item>
</template>
<template v-slot:selection="{ attr, on, item, selected }">
<v-chip
v-bind="attr"
:input-value="selected"
color="blue-grey"
class="white--text"
v-on="on"
>
<v-icon left>mdi-coin</v-icon>
<span v-text="item.name"></span>
</v-chip>
</template>
<template v-slot:item="{ item }">
<v-list-item-avatar
color="indigo"
class="headline font-weight-light white--text"
>
{{ item.name.charAt(0) }}
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="item.name"></v-list-item-title>
<v-list-item-subtitle v-text="item.symbol"></v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-icon>mdi-coin</v-icon>
</v-list-item-action>
</template>
</v-autocomplete>
<template v-slot:extension>
<v-tabs
v-model="tab"
:hide-slider="!model"
color="blue-grey"
slider-color="blue-grey"
>
<v-tab :disabled="!model">News</v-tab>
<v-tab :disabled="!model">Trading</v-tab>
<v-tab :disabled="!model">Blog</v-tab>
</v-tabs>
</template>
</v-toolbar>
</template>
<script>
export default {
data: () => ({
isLoading: false,
items: [],
model: null,
search: null,
tab: null,
}),
watch: {
model (val) {
if (val != null) this.tab = 0
else this.tab = null
},
search (val) {
// Items have already been loaded
if (this.items.length > 0) return
this.isLoading = true
// Lazily load input items
fetch('https://api.coingecko.com/api/v3/coins/list')
.then(res => res.clone().json())
.then(res => {
this.items = res
})
.catch(err => {
console.log(err)
})
.finally(() => (this.isLoading = false))
},
},
}
</script>
状态选择器
结合使用 v-autocomplete
插槽和过渡,您可以创建一个时尚的可切换自动完成字段,例如此状态选择器。
template script
<template>
<v-card>
<v-card-title class="headline font-weight-regular blue-grey white--text">Profile</v-card-title>
<v-card-text>
<v-subheader class="pa-0">Where do you live?</v-subheader>
<v-autocomplete
v-model="model"
:hint="!isEditing ? 'Click the icon to edit' : 'Click the icon to save'"
:items="states"
:readonly="!isEditing"
:label="`State — ${isEditing ? 'Editable' : 'Readonly'}`"
persistent-hint
prepend-icon="mdi-city"
>
<template v-slot:append-outer>
<v-slide-x-reverse-transition
mode="out-in"
>
<v-icon
:key="`icon-${isEditing}`"
:color="isEditing ? 'success' : 'info'"
@click="isEditing = !isEditing"
v-text="isEditing ? 'mdi-check-outline' : 'mdi-circle-edit-outline'"
></v-icon>
</v-slide-x-reverse-transition>
</template>
</v-autocomplete>
</v-card-text>
</v-card>
</template>
<script>
export default {
data () {
return {
isEditing: false,
model: null,
states: [
'Alabama', 'Alaska', 'American Samoa', 'Arizona',
'Arkansas', 'California', 'Colorado', 'Connecticut',
'Delaware', 'District of Columbia', 'Federated States of Micronesia',
'Florida', 'Georgia', 'Guam', 'Hawaii', 'Idaho',
'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky',
'Louisiana', 'Maine', 'Marshall Islands', 'Maryland',
'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi',
'Missouri', 'Montana', 'Nebraska', 'Nevada',
'New Hampshire', 'New Jersey', 'New Mexico', 'New York',
'North Carolina', 'North Dakota', 'Northern Mariana Islands', 'Ohio',
'Oklahoma', 'Oregon', 'Palau', 'Pennsylvania', 'Puerto Rico',
'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee',
'Texas', 'Utah', 'Vermont', 'Virgin Island', 'Virginia',
'Washington', 'West Virginia', 'Wisconsin', 'Wyoming',
],
}
},
}
</script>