Autocomplete
自动完成输入框
Markup Schema 基础用法
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { Autocomplete, FormItem, Submit } from '@silver-formily/element-plus'
import { createSchemaField, FormProvider } from '@silver-formily/vue'
const form = createForm()
const { SchemaField, SchemaStringField } = createSchemaField({
components: {
FormItem,
Autocomplete,
},
})
const cityOptions = [
{ value: '北京' },
{ value: '上海' },
{ value: '广州' },
{ value: '深圳' },
{ value: '杭州' },
{ value: '成都' },
]
async function log(value: any) {
console.log(value)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField>
<SchemaStringField
name="city"
title="常用城市"
x-decorator="FormItem"
x-component="Autocomplete"
:x-component-props="{
triggerOnFocus: true,
placeholder: '请输入或选择城市',
style: { width: '260px' },
}"
:enum="cityOptions"
/>
</SchemaField>
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>常用城市:
查看源码
Markup Schema 远程搜索
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { Autocomplete, FormItem, Submit } from '@silver-formily/element-plus'
import { createSchemaField, FormProvider } from '@silver-formily/vue'
const form = createForm()
const { SchemaField, SchemaStringField } = createSchemaField({
components: {
FormItem,
Autocomplete,
},
})
const languageOptions = [
{ value: 'JavaScript' },
{ value: 'TypeScript' },
{ value: 'Python' },
{ value: 'Rust' },
{ value: 'Go' },
{ value: 'Java' },
{ value: 'C#' },
]
function remoteFetch(query: string, cb: (items: typeof languageOptions) => void) {
const keyword = query?.toLowerCase() ?? ''
const results = keyword
? languageOptions.filter(item => item.value.toLowerCase().includes(keyword))
: languageOptions
setTimeout(() => cb(results), 400)
}
async function log(value: any) {
console.log(value)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField>
<SchemaStringField
name="language"
title="远程搜索"
x-decorator="FormItem"
x-component="Autocomplete"
:x-component-props="{
debounce: 200,
placeholder: '输入语言关键词',
fetchSuggestions: remoteFetch,
style: { width: '280px' },
}"
/>
</SchemaField>
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>远程搜索:
查看源码
Template 作用域插槽
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { Autocomplete, FormItem, Submit } from '@silver-formily/element-plus'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm()
const libraryOptions = [
{ value: 'Vue.js', description: '轻量且易上手的 MVVM 框架' },
{ value: 'React', description: '由 Meta 推出的声明式 UI 库' },
{ value: 'Svelte', description: '编译时框架,运行时代码体积小' },
{ value: 'SolidJS', description: '细粒度响应式系统' },
{ value: 'Angular', description: '完善的一体化框架' },
]
async function log(value: any) {
console.log(value)
}
</script>
<template>
<FormProvider :form="form">
<Field
name="library"
title="框架选择"
:decorator="[FormItem]"
:component="[
Autocomplete,
{
triggerOnFocus: true,
placeholder: '请选择你喜欢的框架',
style: { width: '320px' },
},
]"
:data-source="libraryOptions"
>
<template #default="{ item, field }">
<div class="demo-autocomplete-item">
<div class="demo-autocomplete-item__meta">
<strong>{{ item.value }}</strong>
<span>{{ item.description }}</span>
</div>
<span class="demo-autocomplete-item__hint">
当前值:{{ field?.value?.value ?? '未选择' }}
</span>
</div>
</template>
</Field>
<Submit style="margin-top: 12px" @submit="log">
提交
</Submit>
</FormProvider>
</template>
<style scoped>
.demo-autocomplete-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 8px;
}
.demo-autocomplete-item__meta {
display: flex;
flex-direction: column;
}
.demo-autocomplete-item__meta strong {
font-weight: 600;
}
.demo-autocomplete-item__meta span {
font-size: 12px;
color: var(--vp-c-text-2);
}
.demo-autocomplete-item__hint {
font-size: 12px;
color: var(--vp-c-text-3);
}
</style>框架选择:
查看源码
Template 插槽拓展
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { Autocomplete, FormItem, Submit } from '@silver-formily/element-plus'
import { Field, FormProvider } from '@silver-formily/vue'
import { ref } from 'vue'
const form = createForm()
const loading = ref(false)
const libraries = [
{ value: 'Vue.js', description: '轻量且渐进式的 MVVM 框架' },
{ value: 'React', description: '由 Meta 推出的声明式 UI 库' },
{ value: 'Svelte', description: '编译时框架,运行时代码体积更小' },
{ value: 'SolidJS', description: '细粒度响应式系统' },
{ value: 'Angular', description: '自带完整方案的一体化框架' },
]
function fetchLibraries(query: string, cb: (data: typeof libraries) => void) {
loading.value = true
const keyword = query?.toLowerCase() ?? ''
setTimeout(() => {
const results = keyword
? libraries.filter(item => item.value.toLowerCase().includes(keyword))
: libraries
cb(results)
loading.value = false
}, 500)
}
async function log(value: any) {
console.log(value)
}
</script>
<template>
<FormProvider :form="form">
<Field
name="library"
title="推荐框架"
:decorator="[FormItem]"
:component="[
Autocomplete,
{
triggerOnFocus: true,
fetchSuggestions: fetchLibraries,
placeholder: '搜索或选择框架',
style: { width: '320px' },
},
]"
>
<template #prefix>
<span class="demo-autocomplete-chip">框架</span>
</template>
<template #suffix>
<span class="demo-autocomplete-shortcut">⌘ K</span>
</template>
<template #header="{ field }">
<div class="demo-autocomplete-header">
最近一次选择:{{ field?.value ?? '暂无' }}
</div>
</template>
<template #default="{ item }">
<div class="demo-autocomplete-item">
<strong>{{ item.value }}</strong>
<span>{{ item.description }}</span>
</div>
</template>
<template #loading>
<div class="demo-autocomplete-loading">
正在加载候选...
</div>
</template>
<template #footer>
<div class="demo-autocomplete-footer">
没有找到想要的框架?
<a href="https://github.com/vuejs" target="_blank" rel="noreferrer">点此反馈</a>
</div>
</template>
</Field>
<Submit style="margin-top: 16px" @submit="log">
提交
</Submit>
</FormProvider>
</template>
<style scoped>
.demo-autocomplete-chip {
display: inline-flex;
align-items: center;
padding: 0 6px;
font-size: 12px;
background-color: var(--vp-c-bg-soft);
border-radius: 4px;
color: var(--vp-c-text-1);
}
.demo-autocomplete-shortcut {
font-size: 12px;
color: var(--vp-c-text-3);
}
.demo-autocomplete-header,
.demo-autocomplete-footer {
padding: 6px 12px;
font-size: 12px;
color: var(--vp-c-text-2);
}
.demo-autocomplete-item {
display: flex;
flex-direction: column;
padding: 6px 12px;
line-height: 1.4;
}
.demo-autocomplete-item strong {
font-size: 13px;
color: var(--vp-c-text-1);
}
.demo-autocomplete-item span {
font-size: 12px;
color: var(--vp-c-text-3);
}
.demo-autocomplete-loading {
padding: 8px 12px;
font-size: 12px;
color: var(--vp-c-text-2);
}
</style>推荐框架:
框架⌘ K
查看源码
获取实例
用于获取 ElAutocomplete 实例,方便调用 focus/blur 等方法,类型与 Element Plus 保持一致。
ts
const autocompleteRef = fieldRef.value?.invoke('getElAutocompleteRef')API
参考 https://cn.element-plus.org/zh-CN/component/autocomplete.html
扩展属性
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| options | array | 选项配置数组,等价于 dataSource,在未显式提供 fetchSuggestions 时会自动转为建议列表 | [] |
- 组件会在没有
fetchSuggestions时,基于dataSource / options自动实现本地模糊过滤。 - 当你自定义
fetchSuggestions(query, cb, field)时,第三个field参数会暴露当前 Formily 字段实例,你需要手动赋值field.loading来标明field的状态(从语义化角度考虑是有意义的,大部分时候没有这个必要),更多时候是通过field访问表单的其他Field的值。
例如:
ts
function remoteFetch(query: string, cb: (data: Option[]) => void, field?: Field) {
field && (field.loading = true)
apiRequest(query).finally((resp) => {
cb(resp.data)
field && (field.loading = false)
})
}插槽
组件继承了 Element Plus ElAutocomplete 的全部插槽。其中default、header、footer 插槽额外注入了 Formily field 引用,便于在建议项里访问表单态。
| 插槽名 | 描述 | 类型 |
|---|---|---|
| default | 自定义输入建议内容 | object |
| header | 下拉列表顶部内容 | object |
| footer | 下拉列表底部内容 | object |
| loading | 自定义加载状态内容 | -- |
| prefix | 输入框头部内容 | -- |
| suffix | 输入框尾部内容 | -- |
| prepend | 输入框前置内容(位于 prefix 之前) | -- |
| append | 输入框后置内容(位于 suffix 之后) | -- |