Autocomplete 自动补全
根据当前输入获取一些推荐提示。
基础用法
Autocomplete 组件提供输入建议。
fetch-suggestions
属性是一个返回建议输入的方法。在这个例子中,当建议准备好时,querySearch(queryString, cb)
通过 cb(data)
向 Autocomplete 返回建议。
激活时列出建议
输入时列出建议
vue
<template>
<div class="demo-autocomplete">
<div class="demo-block">
<div class="demo-title">list suggestions when activated</div>
<el-autocomplete
v-model="state1"
:fetch-suggestions="querySearch"
clearable
class="w-50"
placeholder="Please Input"
@select="handleSelect"
/>
</div>
<div class="demo-block">
<div class="demo-title">list suggestions on input</div>
<el-autocomplete
v-model="state2"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
clearable
class="w-50"
placeholder="Please Input"
@select="handleSelect"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
interface RestaurantItem {
value: string
link: string
}
const state1 = ref('')
const state2 = ref('')
const restaurants = ref<RestaurantItem[]>([])
const querySearch = (queryString: string, cb: any) => {
const results = queryString
? restaurants.value.filter(createFilter(queryString))
: restaurants.value
// call callback function to return suggestions
cb(results)
}
const createFilter = (queryString: string) => {
return (restaurant: RestaurantItem) => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
)
}
}
const loadAll = () => {
return [
{ value: 'vue', link: 'https://github.com/vuejs/vue' },
{ value: 'element', link: 'https://github.com/ElemeFE/element' },
{ value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
{ value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
{ value: 'vuex', link: 'https://github.com/vuejs/vuex' },
{ value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
{ value: 'babel', link: 'https://github.com/babel/babel' },
]
}
const handleSelect = (item: Record<string, any>) => {
console.log(item)
}
onMounted(() => {
restaurants.value = loadAll()
})
</script>
<style scoped>
.demo-autocomplete {
display: flex;
flex-wrap: wrap;
gap: 2rem;
}
.demo-block {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.demo-title {
font-size: 0.875rem;
color: var(--el-text-color-secondary);
min-height: 2.5em;
display: flex;
align-items: center;
}
@media screen and (max-width: 768px) {
.demo-autocomplete {
gap: 1rem;
}
.demo-block {
width: 100%;
}
}
</style>
隐藏源代码
自定义模板
自定义建议的显示方式。
使用 scoped slot
自定义建议项。在作用域中,您可以通过 item
键访问建议对象。
vue
<template>
<el-autocomplete
v-model="state"
:fetch-suggestions="querySearch"
popper-class="my-autocomplete"
placeholder="Please input"
@select="handleSelect"
>
<template #suffix>
<el-icon class="el-input__icon" @click="handleIconClick">
<edit />
</el-icon>
</template>
<template #default="{ item }">
<div class="value">{{ item.value }}</div>
<span class="link">{{ item.link }}</span>
</template>
</el-autocomplete>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { Edit } from '@element-plus/icons-vue'
interface LinkItem {
value: string
link: string
}
const state = ref('')
const links = ref<LinkItem[]>([])
const querySearch = (queryString: string, cb) => {
const results = queryString
? links.value.filter(createFilter(queryString))
: links.value
// call callback function to return suggestion objects
cb(results)
}
const createFilter = (queryString: string) => {
return (restaurant: LinkItem) => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
)
}
}
const loadAll = () => {
return [
{ value: 'vue', link: 'https://github.com/vuejs/vue' },
{ value: 'element', link: 'https://github.com/ElemeFE/element' },
{ value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
{ value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
{ value: 'vuex', link: 'https://github.com/vuejs/vuex' },
{ value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
{ value: 'babel', link: 'https://github.com/babel/babel' },
]
}
const handleSelect = (item: Record<string, any>) => {
console.log(item)
}
const handleIconClick = (ev: Event) => {
console.log(ev)
}
onMounted(() => {
links.value = loadAll()
})
</script>
<style>
.my-autocomplete li {
line-height: normal;
padding: 7px;
}
.my-autocomplete li .name {
text-overflow: ellipsis;
overflow: hidden;
}
.my-autocomplete li .addr {
font-size: 12px;
color: #b4b4b4;
}
.my-autocomplete li .highlighted .addr {
color: #ddd;
}
</style>
隐藏源代码
远程搜索
从服务器端搜索数据。
vue
<template>
<el-autocomplete
v-model="state"
:fetch-suggestions="querySearchAsync"
placeholder="Please input"
@select="handleSelect"
/>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
const state = ref('')
interface LinkItem {
value: string
link: string
}
const links = ref<LinkItem[]>([])
const loadAll = () => {
return [
{ value: 'vue', link: 'https://github.com/vuejs/vue' },
{ value: 'element', link: 'https://github.com/ElemeFE/element' },
{ value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
{ value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
{ value: 'vuex', link: 'https://github.com/vuejs/vuex' },
{ value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
{ value: 'babel', link: 'https://github.com/babel/babel' },
]
}
let timeout: ReturnType<typeof setTimeout>
const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
const results = queryString
? links.value.filter(createFilter(queryString))
: links.value
clearTimeout(timeout)
timeout = setTimeout(() => {
cb(results)
}, 3000 * Math.random())
}
const createFilter = (queryString: string) => {
return (restaurant: LinkItem) => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
)
}
}
const handleSelect = (item: Record<string, any>) => {
console.log(item)
}
onMounted(() => {
links.value = loadAll()
})
</script>
隐藏源代码
自定义加载 2.5.0
覆盖加载内容。
加载图标1
加载图标2
vue
<template>
<div class="demo-autocomplete">
<div class="demo-block">
<div class="demo-title">loading icon1</div>
<el-autocomplete
v-model="state"
:fetch-suggestions="querySearchAsync"
class="w-50"
placeholder="Please input"
@select="handleSelect"
>
<template #loading>
<svg class="circular" viewBox="0 0 50 50">
<circle class="path" cx="25" cy="25" r="20" fill="none" />
</svg>
</template>
</el-autocomplete>
</div>
<div class="demo-block">
<div class="demo-title">loading icon2</div>
<el-autocomplete
v-model="state"
:fetch-suggestions="querySearchAsync"
class="w-50"
placeholder="Please input"
@select="handleSelect"
>
<template #loading>
<el-icon class="is-loading">
<svg class="circular" viewBox="0 0 20 20">
<g
class="path2 loading-path"
stroke-width="0"
style="animation: none; stroke: none"
>
<circle r="3.375" class="dot1" rx="0" ry="0" />
<circle r="3.375" class="dot2" rx="0" ry="0" />
<circle r="3.375" class="dot4" rx="0" ry="0" />
<circle r="3.375" class="dot3" rx="0" ry="0" />
</g>
</svg>
</el-icon>
</template>
</el-autocomplete>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
const state = ref('')
interface LinkItem {
value: string
link: string
}
const links = ref<LinkItem[]>([])
const loadAll = () => {
return [
{ value: 'vue', link: 'https://github.com/vuejs/vue' },
{ value: 'element', link: 'https://github.com/ElemeFE/element' },
{ value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
{ value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
{ value: 'vuex', link: 'https://github.com/vuejs/vuex' },
{ value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
{ value: 'babel', link: 'https://github.com/babel/babel' },
]
}
let timeout: ReturnType<typeof setTimeout>
const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
const results = queryString
? links.value.filter(createFilter(queryString))
: links.value
clearTimeout(timeout)
timeout = setTimeout(() => {
cb(results)
}, 5000 * Math.random())
}
const createFilter = (queryString: string) => {
return (restaurant: LinkItem) => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
)
}
}
const handleSelect = (item: Record<string, any>) => {
console.log(item)
}
onMounted(() => {
links.value = loadAll()
})
</script>
<style scoped>
.demo-autocomplete {
display: flex;
flex-wrap: wrap;
gap: 2rem;
}
.demo-block {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.demo-title {
font-size: 0.875rem;
color: var(--el-text-color-secondary);
min-height: 2.5em;
display: flex;
align-items: center;
}
@media screen and (max-width: 768px) {
.demo-autocomplete {
gap: 1rem;
}
.demo-block {
width: 100%;
}
}
</style>
<style>
.circular {
display: inline;
height: 30px;
width: 30px;
animation: loading-rotate 2s linear infinite;
}
.path {
animation: loading-dash 1.5s ease-in-out infinite;
stroke-dasharray: 90, 150;
stroke-dashoffset: 0;
stroke-width: 2;
stroke: var(--el-color-primary);
stroke-linecap: round;
}
.loading-path .dot1 {
transform: translate(3.75px, 3.75px);
fill: var(--el-color-primary);
animation: custom-spin-move 1s infinite linear alternate;
opacity: 0.3;
}
.loading-path .dot2 {
transform: translate(calc(100% - 3.75px), 3.75px);
fill: var(--el-color-primary);
animation: custom-spin-move 1s infinite linear alternate;
opacity: 0.3;
animation-delay: 0.4s;
}
.loading-path .dot3 {
transform: translate(3.75px, calc(100% - 3.75px));
fill: var(--el-color-primary);
animation: custom-spin-move 1s infinite linear alternate;
opacity: 0.3;
animation-delay: 1.2s;
}
.loading-path .dot4 {
transform: translate(calc(100% - 3.75px), calc(100% - 3.75px));
fill: var(--el-color-primary);
animation: custom-spin-move 1s infinite linear alternate;
opacity: 0.3;
animation-delay: 0.8s;
}
@keyframes loading-rotate {
to {
transform: rotate(360deg);
}
}
@keyframes loading-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -40px;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120px;
}
}
@keyframes custom-spin-move {
to {
opacity: 1;
}
}
</style>
隐藏源代码
自定义页眉和页脚 2.10.6
您可以使用插槽自定义下拉列表的页眉和页脚
使用插槽来自定义内容。
自定义页眉内容
自定义页脚内容
vue
<template>
<div class="demo">
<div>
<p>Custom header content</p>
<el-autocomplete
v-model="headerSlotState"
:fetch-suggestions="querySearchAsync"
placeholder="Please input"
@select="handleSelect"
>
<template #header>header content</template>
</el-autocomplete>
</div>
<div>
<p>Custom footer content</p>
<el-autocomplete
ref="footerAutocompleteRef"
v-model="footerSlotstate"
:fetch-suggestions="querySearchAsync"
placeholder="Please input"
@select="handleSelect"
>
<template #footer>
<el-button link size="small" @click="handleClear"> Clear </el-button>
</template>
</el-autocomplete>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
const headerSlotState = ref('')
const footerSlotstate = ref('')
interface LinkItem {
value: string
link: string
}
const links = ref<LinkItem[]>([])
const loadAll = () => {
return [
{ value: 'vue', link: 'https://github.com/vuejs/vue' },
{ value: 'element', link: 'https://github.com/ElemeFE/element' },
{ value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
{ value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
{ value: 'vuex', link: 'https://github.com/vuejs/vuex' },
{ value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
{ value: 'babel', link: 'https://github.com/babel/babel' },
]
}
let timeout: ReturnType<typeof setTimeout>
const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
const results = queryString
? links.value.filter(createFilter(queryString))
: links.value
clearTimeout(timeout)
timeout = setTimeout(() => {
cb(results)
}, 3000 * Math.random())
}
const createFilter = (queryString: string) => {
return (restaurant: LinkItem) => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
)
}
}
const handleSelect = (item: Record<string, any>) => {
console.log(item)
}
onMounted(() => {
links.value = loadAll()
})
const footerAutocompleteRef = ref()
const handleClear = () => {
footerSlotstate.value = ''
footerAutocompleteRef.value.getData()
}
</script>
<style>
.demo {
display: flex;
}
.demo > div {
flex: 1;
text-align: center;
}
.demo > div > .el-autocomplete {
width: 50%;
}
.demo > div:not(:last-child) {
border-right: 1px solid var(--el-border-color);
}
</style>
隐藏源代码
API
属性
名称 | 描述 | 类型 | 默认值 |
---|---|---|---|
model-value / v-model | 绑定值 | string | — |
占位符 | Autocomplete 的占位符 | string | — |
可清空 | 是否显示清除按钮 | boolean | false |
disabled | Autocomplete 是否被禁用 | boolean | false |
value-key | 用于显示的输入建议对象的键名 | string | value |
防抖 | 输入时的防抖延迟,单位为毫秒 | number | 300 |
placement | 弹出菜单的位置 | 枚举 | 下左 |
获取建议 | 一个获取输入建议的方法。当建议准备好时,调用 `callback(data:[])` 将它们返回给 Autocomplete | Array / Function | — |
聚焦时触发 | 输入框聚焦时是否显示建议 | boolean | true |
不匹配时选择 | 在没有自动补全匹配时,按回车键是否触发一个 `select` 事件 | boolean | false |
名称 | 与原生输入框的 `name` 相同 | string | — |
aria-label a11y 2.7.2 | 原生的 `aria-label` 属性 | string | — |
隐藏加载 | 在远程搜索中是否隐藏加载图标 | boolean | false |
popper-class | 自动补全下拉列表的自定义类名 | string | — |
teleported | 选择下拉框是否被传送到 body | boolean | true |
追加至 2.9.9 | 选择下拉框追加到哪个元素 | CSSSelector / HTMLElement | — |
高亮第一项 | 在远程搜索建议中是否默认高亮第一项 | boolean | false |
fit-input-width | 下拉框的宽度是否与输入框相同 | boolean | false |
popper-append-to-body 已弃用 | 是否将下拉列表追加到 body。如果下拉列表的定位错误,可以尝试将此属性设置为 false | boolean | false |
输入框属性 | — | — | — |
事件
名称 | 描述 | 类型 |
---|---|---|
blur | 在 Input 失去焦点时触发 | Function |
focus | 在 Input 获得焦点时触发 | Function |
input | 在 Input 值改变时触发 | Function |
clear | 在点击清除按钮清空 Input 时触发 | Function |
select | 点击建议时触发 | Function |
change | 当输入框内的图标值改变时触发 | Function |
插槽
名称 | 描述 | 类型 |
---|---|---|
default | 输入建议的自定义内容 | object |
头部 2.10.6 | 下拉列表顶部的内容 | - |
尾部 2.10.6 | 下拉列表底部的内容 | - |
prefix | 作为输入框前缀的内容 | - |
suffix | 作为输入框后缀的内容 | - |
prepend | 在输入框前添加的内容 | - |
append | 在输入框后添加的内容 | - |
加载中 2.5.0 | 覆盖加载内容 | - |
暴露
名称 | 描述 | 类型 |
---|---|---|
已激活 | 如果自动补全已激活 | object |
blur | 使输入框元素失焦 | Function |
关闭 | 折叠建议列表 | Function |
focus | 使输入框元素聚焦 | Function |
处理选择 | 点击建议时触发 | Function |
处理回车键 | 处理键盘回车事件 | Function |
高亮索引 | 当前高亮项的索引 | object |
高亮 | 高亮建议中的一项 | Function |
输入框引用 | el-input 组件实例 | object |
加载中 | 远程搜索加载指示器 | object |
popperRef | el-tooltip 组件实例 | object |
建议 | 获取建议结果 | object |
获取数据 2.8.4 | 加载建议列表 | Function |