diff --git a/packages/devui-vue/devui/auto-complete/__tests__/auto-complete.spec.ts b/packages/devui-vue/devui/auto-complete/__tests__/auto-complete.spec.ts
new file mode 100644
index 0000000000..85df305ba4
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/__tests__/auto-complete.spec.ts
@@ -0,0 +1,570 @@
+import { mount } from '@vue/test-utils';
+import { nextTick, ref } from 'vue';
+import DAutoComplete from '../src/auto-complete';
+
+// delay api
+const wait = (delay = 300) =>
+ new Promise(resolve => setTimeout(() => resolve(true), delay))
+describe('auto-complete', () => {
+ it('init render & KeyboardEvent ', async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+ `,
+ setup() {
+ const value = ref('')
+ const source = [
+ 'C#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'CoffeeScript',
+ ]
+ return {
+ value,
+ source,
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('click')
+ await nextTick()
+ expect(wrapper.find('.devui-select-open').exists()).toBe(true)
+ expect(wrapper.find('.devui-dropdown-item').exists()).toBe(false)
+ expect(wrapper.find('.devui-auto-complete').attributes('style')).toContain(
+ 'width: 450px'
+ )
+ await input.setValue('c')
+ await nextTick()
+ expect(wrapper.find('.devui-dropdown-menu').exists()).toBe(true)
+ await wait(300)
+ await nextTick()
+ expect(wrapper.find('.devui-list-unstyled').element.childElementCount).toBe(5)
+ input.element.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
+ await nextTick()
+ input.element.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
+ await nextTick()
+ input.element.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
+ await nextTick()
+ input.element.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
+ await nextTick()
+ input.element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))
+ await nextTick()
+ expect(wrapper.vm.value).toBe('C++')
+ input.element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))
+ await nextTick()
+ expect(wrapper.find('.devui-select-open').exists()).toBe(false)
+ })
+ it('disabled ', async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+
+
+
+ `,
+ setup() {
+ const value = ref('')
+ const isDisabled = ref(false)
+ const source = [
+ 'C#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'CoffeeScript',
+ ]
+ function toggle(){
+ isDisabled.value= !isDisabled.value
+ }
+ return {
+ value,
+ source,
+ isDisabled,
+ toggle
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ const button = wrapper.find('button')
+ expect(input.element.value).toBe('')
+ expect(button.element.innerHTML).toBe('Disable AutoComplete')
+ await input.trigger('click')
+ await nextTick()
+ await input.setValue('c')
+ await nextTick()
+ await wait(300)
+ await nextTick()
+ expect(wrapper.find('ul .selected').exists()).toBe(true)
+ const li = wrapper.find('ul .selected')
+ li.trigger('click')
+ await nextTick()
+ expect(wrapper.vm.value).toBe('C#')
+ expect(wrapper.find('.devui-select-open').exists()).toBe(false)
+ button.trigger('click')
+ await nextTick()
+ expect(button.element.innerHTML).toBe('Enable AutoComplete')
+ expect(input.element.disabled).toBe(true)
+ })
+ it('Customized data matching method ', async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+
+
+ {{slotProps}}
+
+
+
+ `,
+ setup() {
+ const value = ref('')
+ const mySource = ref([
+ {
+ label:'C#',
+ disabled:false
+ },{
+ label:'C++',
+ disabled:false
+ },{
+ label:'CPython',
+ disabled:false
+ },{
+ label:'Java',
+ disabled:false
+ },{
+ label:'JavaScript',
+ disabled:false
+ },{
+ label:'Go',
+ disabled:false
+ },{
+ label:'Ruby',
+ disabled:false
+ },{
+ label:'F#',
+ disabled:false
+ },{
+ label:'TypeScript',
+ disabled:false
+ },{
+ label:'SQL',
+ disabled:true
+ },{
+ label:'LiveScript',
+ disabled:false
+ },{
+ label:'CoffeeScript',
+ disabled:false
+ }
+ ])
+ const formatter = (item) =>{
+ return item.label;
+ }
+ //trem:input输入内容
+ const searchFn =async (trem)=>{
+ const arr = []
+ await new Promise((resolve)=>{
+ setTimeout(() => {
+ resolve(1)
+ }, 500);
+ })
+ mySource.value.forEach((item) => {
+ let cur = item.label
+ cur = cur.toLowerCase()
+ if (cur.startsWith(trem)) {
+ arr.push(item)
+ }
+ })
+ return arr
+ }
+ return {
+ value,
+ searchFn,
+ formatter
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('click')
+ await nextTick()
+ expect(wrapper.find('.devui-select-open').exists()).toBe(true)
+ await input.setValue('c')
+ await nextTick()
+ await wait(300)
+ expect(wrapper.find('#devui-is-searching-template').exists()).toBe(true)
+ expect(wrapper.find('#devui-is-searching-template').element.innerHTML).toBe('c')
+ await wait(500)
+ await nextTick()
+ expect(wrapper.find('.devui-list-unstyled').element.childElementCount).toBe(4)
+ await input.setValue('s')
+ await nextTick()
+ await wait(300)
+ await nextTick()
+ await wait(500)
+ expect(wrapper.find('li.disabled').exists()).toBe(true)
+ expect(wrapper.find('li.disabled').element.innerHTML).toBe('SQL')
+ })
+
+ it('Customized template display', async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+
+
+ 第{{slotProps.index}}项: {{slotProps.item}}
+
+
+
+
+ {{slotProps}}
+
+
+
+ `,
+ setup() {
+ const value = ref('')
+ const source = ref([
+ 'C#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'Java',
+ 'JavaScript',
+ 'Go',
+ 'Python',
+ 'Ruby',
+ 'F#',
+ 'TypeScript',
+ 'SQL',
+ 'LiveScript',
+ 'CoffeeScript',
+ ])
+
+ return {
+ value,
+ source
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('click')
+ await nextTick()
+ expect(wrapper.find('.devui-select-open').exists()).toBe(true)
+ await input.setValue('c')
+ await nextTick()
+ await wait(300)
+ expect(wrapper.find('.devui-list-unstyled').exists()).toBe(true)
+ expect(wrapper.find('.devui-list-unstyled').element.childElementCount).toBe(5)
+ expect(wrapper.find('.selected div').element.innerHTML).toBe(' 第0项: C#')
+ await input.setValue('cc')
+ await nextTick()
+ await wait(300)
+ await nextTick()
+ expect(wrapper.find('#noResultItemTemplate').exists()).toBe(true)
+ expect(wrapper.find('#noResultItemTemplate').element.innerHTML).toBe('cc')
+ })
+
+ it('selectValue & transInputFocusEmit ', async () => {
+ const transInputFocusEmitCB = jest.fn()
+ const selectValueCB = jest.fn()
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+ `,
+ setup() {
+ const value = ref('')
+ const source = [
+ 'C#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'CoffeeScript',
+ ]
+ const selectValue = (e)=>{
+ selectValueCB(e)
+ }
+ const transInputFocusEmit = (e)=>{
+ transInputFocusEmitCB(e)
+ }
+ return {
+ value,
+ source,
+ selectValue,
+ transInputFocusEmit
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('focus')
+ await nextTick()
+ await input.setValue('c')
+ await nextTick()
+ await wait(300)
+ await nextTick()
+ expect(transInputFocusEmitCB).toHaveBeenCalledTimes(1)
+ const li = wrapper.find('ul .selected')
+ li.trigger('click')
+ await nextTick()
+ expect(selectValueCB).toHaveBeenCalledTimes(1)
+ })
+ it('allowEmptyValueSearch ', async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+ `,
+ setup() {
+ const value = ref('')
+ const allowEmptyValueSearch = ref(true)
+ const source = [
+ 'C#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'CoffeeScript',
+ ]
+
+ return {
+ value,
+ source,
+ allowEmptyValueSearch
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('focus')
+ await nextTick()
+ expect(wrapper.find('ul').element.childElementCount).toBe(5)
+ })
+
+ it('appendToBody & appendToBodyDirections', async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template: `
+
+ `,
+ setup() {
+ const value = ref('')
+ const allowEmptyValueSearch = ref(true)
+ const source = [
+ 'CC#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'CoffeeScript',
+ ]
+ const appendToBodyDirections = ref({
+ originX: 'left',
+ originY: 'bottom',
+ overlayX: 'left',
+ overlayY: 'top',
+ })
+ return {
+ value,
+ source,
+ allowEmptyValueSearch,
+ appendToBodyDirections
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('focus')
+ await nextTick()
+ await input.setValue('c')
+ await nextTick()
+ await wait(300)
+ await nextTick()
+ expect(wrapper.find('ul').element.childElementCount).toBe(5)
+ expect(wrapper.find('.selected').element.innerHTML).toBe('CC#')
+ })
+
+ it('latestSource',async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template:`
+
+
+
+ `,
+ setup(){
+ const value = ref('')
+ const latestSource = ref(['JavaScript','TypeScript'])
+ const source = ref([
+ 'C#',
+ 'C',
+ 'C++',
+ 'Java',
+ 'JavaScript'
+ ])
+
+ return {
+ value,
+ source,
+ latestSource
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.trigger('click')
+ await nextTick()
+ expect(wrapper.find('ul .devui-popup-tips').exists()).toBe(true)
+ await input.setValue('j')
+ await wait(300)
+ await nextTick()
+ const li = wrapper.find('ul .selected')
+ li.trigger('click')
+ await nextTick()
+ expect(wrapper.vm.value).toBe('Java')
+ })
+ it('enableLazyLoad',async () => {
+ const wrapper = mount({
+ components: {'d-auto-complete': DAutoComplete },
+ template:`
+
+
+
+ `,
+ setup(){
+ const value = ref('')
+ const source = ref([
+ 'C#',
+ 'C',
+ 'C++',
+ 'CPython',
+ 'Java',
+ 'JavaScript',
+ 'Go',
+ 'Python',
+ 'Ruby',
+ 'F#',
+ 'TypeScript',
+ 'SQL',
+ 'LiveScript',
+ 'CoffeeScript',
+ 'C1',
+ 'C2',
+ 'C3',
+ 'C4',
+ 'C5',
+ 'C6',
+ 'C7',
+ ])
+ const autoCompleteRef =ref(null)
+
+ const loadMore = () => {
+ setTimeout(() => {
+ source.value.push('lazyData'+source.value.length)
+ autoCompleteRef.value?.loadFinish()
+ },3000)
+ }
+ return {
+ value,
+ source,
+ loadMore,
+ autoCompleteRef
+ }
+ }
+ })
+ expect(wrapper.find('.devui-auto-complete').exists()).toBe(true)
+ const input = wrapper.find('input')
+ expect(input.element.value).toBe('')
+ await input.setValue('c')
+ await nextTick()
+ expect(wrapper.find('.devui-dropdown-menu').exists()).toBe(true)
+ await wait(300)
+ await nextTick()
+ expect(wrapper.find('.devui-dropdown-item').exists()).toBe(true)
+ const ul = wrapper.find('.devui-list-unstyled')
+ const makeScroll = async (
+ dom: Element,
+ name: 'scrollTop',
+ offset: number
+ ) => {
+ const eventTarget = dom === document.documentElement ? window : dom
+ dom[name] = offset
+ const evt = new CustomEvent('scroll', {
+ detail: {
+ target: {
+ [name]: offset,
+ },
+ },
+ })
+ eventTarget.dispatchEvent(evt)
+ return await wait(3000)
+ }
+ await makeScroll(ul.element, 'scrollTop', 500)
+ await nextTick()
+ expect(wrapper.vm.value).toBe('c')
+ await nextTick()
+ await input.setValue('')
+ const length = wrapper.vm.source.length
+ expect(wrapper.vm.source[length - 1]).toBe('lazyData21')
+ await input.setValue('la')
+ await wait(300)
+ await nextTick()
+ expect(wrapper.find('.devui-dropdown-item').element.innerHTML).toBe('lazyData21')
+ })
+})
+
diff --git a/packages/devui-vue/devui/auto-complete/index.ts b/packages/devui-vue/devui/auto-complete/index.ts
new file mode 100644
index 0000000000..ecfbe3545b
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/index.ts
@@ -0,0 +1,17 @@
+import type { App } from 'vue'
+import AutoComplete from './src/auto-complete'
+
+AutoComplete.install = function(app: App): void {
+ app.component(AutoComplete.name, AutoComplete)
+}
+
+export { AutoComplete }
+
+export default {
+ title: 'AutoComplete 自动补全',
+ category: '数据录入',
+ status: '100%',
+ install(app: App): void {
+ app.use(AutoComplete as any)
+ }
+}
diff --git a/packages/devui-vue/devui/auto-complete/src/auto-complete-types.ts b/packages/devui-vue/devui/auto-complete/src/auto-complete-types.ts
new file mode 100644
index 0000000000..b3618cd2f2
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/auto-complete-types.ts
@@ -0,0 +1,140 @@
+import type { PropType, ExtractPropTypes, InjectionKey, SetupContext, Ref } from 'vue'
+const defaultFormatter = (item) => (item ? item.label || item.toString() : '');
+const defaultValueParse = (item) => item;
+// appendToBody使用
+export type HorizontalConnectionPos = 'left' | 'center' | 'right';
+export type VerticalConnectionPos = 'top' | 'center' | 'bottom';
+export interface ConnectionPosition {
+ originX: HorizontalConnectionPos
+ originY: VerticalConnectionPos
+ overlayX: HorizontalConnectionPos
+ overlayY: VerticalConnectionPos
+}
+export const autoCompleteProps = {
+ modelValue: {
+ type: String,
+ default:''
+ },
+ source:{
+ type :Array,
+ default:null
+ },
+ allowEmptyValueSearch:{
+ type:Boolean,
+ default:false
+ },
+ appendToBody :{
+ type:Boolean,
+ default:false
+ },
+ appendToBodyDirections :{
+ type: Object as PropType,
+ default: (): ConnectionPosition => ({
+ originX: 'left',
+ originY: 'bottom',
+ overlayX: 'left',
+ overlayY: 'top',
+ }),
+ },
+ disabled:{
+ type:Boolean,
+ default:false
+ },
+ delay:{
+ type:Number,
+ default:300
+ },
+ disabledKey:{
+ type:String,
+ default:null
+ },
+ formatter: {
+ type:Function as PropType<(item: any) => string>,
+ default:defaultFormatter
+ },
+ isSearching: {
+ type:Boolean,
+ default:false
+ },
+ sceneType:{
+ type:String,
+ default:null
+ },
+ searchFn:{
+ type:Function as PropType<(term: string) => Array>,
+ default:null
+ },
+ tipsText:{
+ type:String,
+ default:'最近输入'
+ },
+ latestSource:{
+ type:Array,
+ default:null
+ },
+ valueParser:{
+ type:Function as PropType<(item: any) => any>,
+ default:defaultValueParse
+ },
+ enableLazyLoad: {
+ type:Boolean,
+ default:false
+ },
+ dAutoCompleteWidth:{
+ type: Number,
+ default:null
+ },
+ showAnimation:{
+ type:Boolean,
+ default:true
+ },
+ maxHeight:{
+ type:Number,
+ default:300
+ },
+ transInputFocusEmit:{
+ type:Function as PropType<(any) => void>,
+ default:null
+ },
+ selectValue:{
+ type:Function as PropType<(any) => void>,
+ default:null
+ },
+ loadMore:{
+ type:Function as PropType<() => void>,
+ default:null
+ }
+} as const
+
+export type AutoCompleteProps = ExtractPropTypes
+
+export interface AutoCompleteRootType {
+ ctx:SetupContext
+ props:AutoCompleteProps
+}
+export type SearchFnType = (term: string) => Array
+export type FormatterType = (item: any) => string
+export type DefaultFuncType = (any?) => any
+export type HandleSearch = (term?:string | string,enableLazyLoad?:boolean) => void
+export type RecentlyFocus = (latestSource:Array) => void
+export type InputDebounceCb = (...rest:any) => Promise
+export type TransInputFocusEmit = (any?: any) => void
+export type SelectOptionClick = (any?: any) => void
+//弹出选择框参数
+export type DropdownProps = {
+ props:AutoCompleteProps
+ searchList:Ref
+ searchStatus?:Ref
+ showNoResultItemTemplate:Ref
+ term?: string
+ visible: Ref
+ selectedIndex:Ref
+ selectOptionClick:HandleSearch
+ dropDownRef
+ showLoading:Ref
+ loadMore
+ latestSource
+ modelValue:Ref
+ hoverIndex:Ref
+}
+export const DropdownPropsKey:InjectionKey=Symbol('DropdownPropsKey')
diff --git a/packages/devui-vue/devui/auto-complete/src/auto-complete.scss b/packages/devui-vue/devui/auto-complete/src/auto-complete.scss
new file mode 100644
index 0000000000..fc4d56c667
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/auto-complete.scss
@@ -0,0 +1,92 @@
+@import '../../style/mixins/index';
+@import '../../style/theme/color';
+.devui-auto-complete,
+.devui-auto-complete-menu {
+ .devui-dropdown-menu {
+ left: 0 !important;
+ top: 0 !important;
+ }
+}
+
+.active {
+ background: $devui-list-item-hover-bg;
+}
+
+.devui-dropdown-menu {
+ width: 100%;
+ display: block;
+}
+
+.devui-dropdown-menu-cdk {
+ position: static;
+}
+
+.devui-dropdown-item {
+ cursor: pointer;
+ display: block;
+ width: 100%;
+ padding: 8px 12px;
+ clear: both;
+ border: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ line-height: 14px;
+}
+
+.devui-dropdown-menu {
+ .devui-dropdown-item:not(.disabled) {
+ &.selected {
+ color: $devui-list-item-active-text;
+ background-color: $devui-list-item-active-bg;
+ }
+ }
+}
+
+.devui-no-result-template,
+.devui-is-searching-template {
+ display: block;
+ width: 100%;
+ padding: 8px 12px;
+ clear: both;
+ border: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ cursor: not-allowed;
+ background-color: $devui-disabled-bg;
+ color: $devui-disabled-text;
+ line-height: 14px;
+
+ &:hover,
+ &:active,
+ &:hover:active {
+ background-color: $devui-unavailable;
+ }
+}
+
+/* 选项disabled */
+.devui-dropdown-item.disabled,
+.devui-dropdown-item.disabled:hover {
+ cursor: not-allowed;
+ color: $devui-disabled-text;
+}
+
+ul.devui-list-unstyled {
+ margin: 0;
+ overflow-y: auto;
+}
+
+.devui-dropdown-bg {
+ background: $devui-list-item-hover-bg;
+ color: $devui-list-item-hover-text;
+}
+
+.devui-popup-tips {
+ color: $devui-text-weak; // TODO: Color-Question
+ padding: 4px 12px;
+}
+
+.devui-dropdown-latestSource ul {
+ line-height: initial !important;
+}
diff --git a/packages/devui-vue/devui/auto-complete/src/auto-complete.tsx b/packages/devui-vue/devui/auto-complete/src/auto-complete.tsx
new file mode 100644
index 0000000000..0f70a1e350
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/auto-complete.tsx
@@ -0,0 +1,127 @@
+import { defineComponent, provide, reactive, Transition,toRefs, ref, SetupContext } from 'vue'
+import { autoCompleteProps, AutoCompleteProps, DropdownPropsKey } from './auto-complete-types'
+import useCustomTemplate from './composables/use-custom-template'
+import useSearchFn from './composables/use-searchfn'
+import useInputHandle from './composables/use-input-handle'
+import useSelectHandle from './composables/use-select-handle'
+import useLazyHandle from './composables/use-lazy-handle'
+import useKeyBoardHandle from './composables/use-keyboard-select'
+import './auto-complete.scss'
+import DAutoCompleteDropdown from './components/dropdown'
+import ClickOutside from '../../shared/devui-directive/clickoutside'
+import {FlexibleOverlay} from '../../overlay/src/flexible-overlay'
+export default defineComponent({
+ name: 'DAutoComplete',
+ directives: { ClickOutside },
+ props: autoCompleteProps,
+ emits: ['update:modelValue'],
+ setup(props: AutoCompleteProps, ctx:SetupContext) {
+ const {
+ disabled,
+ modelValue,
+ appendToBody,
+ dAutoCompleteWidth,
+ delay,
+ allowEmptyValueSearch,
+ formatter,
+ transInputFocusEmit,
+ selectValue,
+ source,
+ searchFn,
+ appendToBodyDirections,
+ latestSource,
+ showAnimation
+ } = toRefs(props)
+
+ const {handleSearch,searchList,showNoResultItemTemplate,recentlyFocus} = useSearchFn(ctx,allowEmptyValueSearch,source,searchFn,formatter)
+ const {onInput,onFocus,inputRef,visible,searchStatus,handleClose,toggleMenu} = useInputHandle(ctx,searchList,showNoResultItemTemplate,modelValue,disabled,delay,handleSearch,transInputFocusEmit,recentlyFocus,latestSource)
+ const {selectedIndex,selectOptionClick} = useSelectHandle(ctx,searchList,selectValue,handleSearch,formatter,handleClose)
+ const {showLoading,dropDownRef,loadMore} = useLazyHandle(props,ctx,handleSearch)
+ const {customRenderSolts} = useCustomTemplate(ctx,modelValue)
+ const {hoverIndex,handlekeyDown} = useKeyBoardHandle(dropDownRef,visible,searchList,selectedIndex,searchStatus,showNoResultItemTemplate,selectOptionClick,handleClose)
+ provide(DropdownPropsKey, {
+ props,
+ visible,
+ term: '',
+ searchList:searchList,
+ selectedIndex,
+ searchStatus,
+ selectOptionClick,
+ dropDownRef,
+ showLoading,
+ loadMore,
+ latestSource,
+ modelValue,
+ showNoResultItemTemplate:showNoResultItemTemplate,
+ hoverIndex:hoverIndex
+ })
+ const origin = ref()
+ const position = reactive({appendToBodyDirections:{}})
+ position.appendToBodyDirections=appendToBodyDirections
+ const renderDropdown = () => {
+ if(appendToBody.value){
+ return (
+
+
+
+ )
+ }else{
+ return (
+ 0&&dAutoCompleteWidth.value+'px'
+ }}
+ >
+
+
+ {customRenderSolts()}
+
+
+
+ )
+ }
+
+ }
+ return () => {
+ return (
+ 0&&dAutoCompleteWidth.value+'px'
+ }}
+ >
+
+ {renderDropdown()}
+
+ )
+ }
+ }
+})
diff --git a/packages/devui-vue/devui/auto-complete/src/components/dropdown.tsx b/packages/devui-vue/devui/auto-complete/src/components/dropdown.tsx
new file mode 100644
index 0000000000..38dd7ed3a3
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/components/dropdown.tsx
@@ -0,0 +1,103 @@
+import { defineComponent, inject } from 'vue'
+import { DropdownPropsKey } from '../auto-complete-types'
+import dLoading from '../../../loading/src/directive'
+// 后续会对接自带下拉组件,相关功能将全部抽离
+export default defineComponent({
+ name: 'DAutoCompleteDropdown',
+ directives: {dLoading},
+ setup(props,ctx) {
+ const propsData = inject(DropdownPropsKey)
+ const {
+ visible,
+ selectedIndex,
+ selectOptionClick,
+ searchList,
+ searchStatus,
+ dropDownRef,
+ loadMore,
+ showLoading,
+ showNoResultItemTemplate,
+ latestSource,
+ modelValue,
+ hoverIndex
+ } = propsData
+ const {
+ disabled,
+ maxHeight,
+ appendToBody,
+ formatter,
+ disabledKey,
+ isSearching,
+ } = propsData.props
+
+ const onSelect =(item:any)=>{
+ if(item[disabledKey]){return}
+ selectOptionClick(item)
+ }
+ return () => {
+ return (
+ 0)||(ctx.slots.noResultItemTemplate&&showNoResultItemTemplate.value)||(isSearching&&ctx.slots.searchingTemplate&&searchStatus.value)}
+ >
+
+
+ )
+ }
+
+ }
+})
\ No newline at end of file
diff --git a/packages/devui-vue/devui/auto-complete/src/composables/use-custom-template.ts b/packages/devui-vue/devui/auto-complete/src/composables/use-custom-template.ts
new file mode 100644
index 0000000000..5ddd8a3ec9
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/composables/use-custom-template.ts
@@ -0,0 +1,37 @@
+import { Ref, SetupContext } from 'vue';
+
+export default function useCustomTemplate(ctx:SetupContext,modelValue:Ref): any {
+ const itemTemplate = (item, index) => {
+ const arr = { item, index }
+ if (ctx.slots.itemTemplate) {
+ return ctx.slots.itemTemplate(arr)
+ }
+ return null
+ }
+ const noResultItemTemplate = () => {
+ if (ctx.slots.noResultItemTemplate) {
+ return ctx.slots.noResultItemTemplate(modelValue.value)
+ }
+ return null
+ }
+ const searchingTemplate = () => {
+ if (ctx.slots.searchingTemplate) {
+ return ctx.slots.searchingTemplate(modelValue.value)
+ }
+ return null
+ }
+ const customRenderSolts = () => {
+ const slots = {}
+ if (ctx.slots.itemTemplate) {
+ slots['itemTemplate'] = itemTemplate
+ }
+ if (ctx.slots.noResultItemTemplate) {
+ slots['noResultItemTemplate'] = noResultItemTemplate
+ }
+ if (ctx.slots.searchingTemplate) {
+ slots['searchingTemplate'] = searchingTemplate
+ }
+ return slots
+ }
+ return {customRenderSolts}
+}
\ No newline at end of file
diff --git a/packages/devui-vue/devui/auto-complete/src/composables/use-input-handle.ts b/packages/devui-vue/devui/auto-complete/src/composables/use-input-handle.ts
new file mode 100644
index 0000000000..090a867276
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/composables/use-input-handle.ts
@@ -0,0 +1,63 @@
+import { ref, Ref, SetupContext } from 'vue';
+import {HandleSearch,RecentlyFocus,InputDebounceCb,TransInputFocusEmit} from '../auto-complete-types'
+export default function useInputHandle(ctx: SetupContext,searchList:Ref,showNoResultItemTemplate:Ref, modelValue:Ref,disabled:Ref,delay:Ref,handleSearch: HandleSearch, transInputFocusEmit:Ref,recentlyFocus:RecentlyFocus,latestSource:Ref>): any {
+ const visible = ref(false)
+ const inputRef = ref()
+ const searchStatus = ref(false)
+ const debounce =(cb:InputDebounceCb,time:number) =>{
+ let timer
+ return (...args)=>{
+ if(timer){
+ clearTimeout(timer)
+ }
+ timer = setTimeout(async ()=>{
+ searchStatus.value=true
+ await cb(...args)
+ searchStatus.value=false
+ },time)
+ }
+ }
+ const onInputCb = async(value:string)=>{
+ await handleSearch(value)
+ visible.value = true
+ }
+ const onInputDebounce = debounce(onInputCb,delay.value)
+ const onInput =(e: Event) => {
+ const inp = e.target as HTMLInputElement
+ searchStatus.value=false
+ showNoResultItemTemplate.value=false
+ ctx.emit('update:modelValue', inp.value)
+ onInputDebounce(inp.value)
+ }
+ const onFocus =() => {
+ handleSearch(modelValue.value)
+ recentlyFocus(latestSource.value)
+ transInputFocusEmit.value && transInputFocusEmit.value()
+ }
+ const handleClose = ()=>{
+ visible.value=false
+ searchStatus.value=false
+ showNoResultItemTemplate.value=false
+ }
+ const toggleMenu =()=>{
+ if(!disabled.value){
+ if(visible.value){
+ handleClose()
+ }else{
+ visible.value=true
+ if (ctx.slots.noResultItemTemplate&&searchList.value.length==0&&modelValue.value.trim()!='') {
+ showNoResultItemTemplate.value=true
+ }
+ }
+ }
+ }
+ return {
+ handleClose,
+ toggleMenu,
+ onInput,
+ onFocus,
+ inputRef,
+ visible,
+ searchStatus
+ }
+}
\ No newline at end of file
diff --git a/packages/devui-vue/devui/auto-complete/src/composables/use-keyboard-select.ts b/packages/devui-vue/devui/auto-complete/src/composables/use-keyboard-select.ts
new file mode 100644
index 0000000000..ad04b34793
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/composables/use-keyboard-select.ts
@@ -0,0 +1,55 @@
+import { nextTick, ref, Ref } from 'vue';
+import { DefaultFuncType, SelectOptionClick } from '../auto-complete-types';
+
+export default function useKeyBoardHandle(dropDownRef: Ref, visible: Ref, searchList: Ref>, selectedIndex: Ref, searchStatus: Ref, showNoResultItemTemplate: Ref, selectOptionClick: SelectOptionClick, handleClose: DefaultFuncType): any {
+ const hoverIndex = ref(selectedIndex.value??0)
+ const scrollToActive = (index: number) => {
+ const ul = dropDownRef.value
+ const li = ul.children[index]
+ nextTick(() => {
+ if (li.scrollIntoViewIfNeeded) {
+ li.scrollIntoViewIfNeeded(false)
+ } else {
+ const containerInfo = ul.getBoundingClientRect()
+ const elementInfo = li.getBoundingClientRect()
+ if (elementInfo.bottom > containerInfo.bottom || elementInfo.top < containerInfo.top) {
+ li.scrollIntoView(false)
+ }
+ }
+ })
+ }
+ const handlekeyDown = (e: KeyboardEvent) => {
+ const keyCode = e.key || e.code
+ if (keyCode === 'Escape' && ( (visible.value && searchList.value.length) || searchStatus.value||showNoResultItemTemplate.value)) {
+ handleClose()
+ return
+ }
+ const status = visible.value && searchList.value.length && !searchStatus.value && !showNoResultItemTemplate.value
+ if (keyCode === 'ArrowDown' && status) {
+ if (hoverIndex.value === searchList.value.length - 1) {
+ hoverIndex.value = 0;
+ scrollToActive(hoverIndex.value);
+ return;
+ }
+ hoverIndex.value = hoverIndex.value + 1;
+ scrollToActive(hoverIndex.value);
+ } else if (keyCode === 'ArrowUp' && status) {
+ if (hoverIndex.value === 0) {
+ hoverIndex.value = searchList.value.length - 1;
+ scrollToActive(hoverIndex.value);
+ return;
+ }
+ hoverIndex.value = hoverIndex.value - 1;
+ scrollToActive(hoverIndex.value);
+ }
+ if (keyCode === 'Enter' && status) {
+ selectOptionClick(searchList.value[hoverIndex.value])
+ hoverIndex.value=selectedIndex.value??0
+ return
+ }
+ }
+ return {
+ hoverIndex,
+ handlekeyDown
+ }
+}
\ No newline at end of file
diff --git a/packages/devui-vue/devui/auto-complete/src/composables/use-lazy-handle.ts b/packages/devui-vue/devui/auto-complete/src/composables/use-lazy-handle.ts
new file mode 100644
index 0000000000..96add63862
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/composables/use-lazy-handle.ts
@@ -0,0 +1,30 @@
+import { ref,SetupContext } from 'vue'
+import { AutoCompleteProps,HandleSearch } from '../auto-complete-types'
+export default function useLazyHandle(props: AutoCompleteProps,ctx:SetupContext,handleSearch:HandleSearch):any {
+ const showLoading = ref(false)
+ const dropDownRef = ref()
+ const loadMore = () => {
+ if(!props.enableLazyLoad && showLoading) return
+ const dropDownValue = dropDownRef.value
+ const height = dropDownValue.scrollHeight
+ const scrollTop = dropDownValue.clientHeight + dropDownValue.scrollTop
+
+ if(scrollTop >= height && scrollTop >= props.maxHeight) {
+ props.loadMore()
+ showLoading.value = true
+ }
+ }
+ ctx.expose({loadFinish})
+
+ async function loadFinish (){
+ await handleSearch(props.modelValue,props.enableLazyLoad)
+ showLoading.value = false
+ }
+ return {
+ showLoading,
+ dropDownRef,
+ loadMore,
+ }
+}
+
+
diff --git a/packages/devui-vue/devui/auto-complete/src/composables/use-searchfn.ts b/packages/devui-vue/devui/auto-complete/src/composables/use-searchfn.ts
new file mode 100644
index 0000000000..8d90a98811
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/composables/use-searchfn.ts
@@ -0,0 +1,45 @@
+import { ref, Ref, SetupContext } from 'vue';
+import { FormatterType, SearchFnType } from '../auto-complete-types';
+export default function useSearchFn(ctx: SetupContext,allowEmptyValueSearch:Ref,source:Ref>,searchFn:Ref,formatter:Ref): any {
+ const searchList = ref([])
+ const showNoResultItemTemplate = ref(false)
+ const handleSearch = async (term: string,enableLazyLoad:boolean) => {
+ if (term == ''&&!allowEmptyValueSearch.value) {
+ searchList.value = []
+ showNoResultItemTemplate.value=false
+ return
+ }
+ let arr = []
+ term = term.toLowerCase()
+ if(enableLazyLoad) {
+ arr = source.value
+ }else if (!searchFn.value) {
+ source.value.forEach((item) => {
+ let cur = formatter.value(item)
+ cur = cur.toLowerCase()
+ if (cur.startsWith(term)) {
+ arr.push(item)
+ }
+ })
+ } else {
+ arr = await searchFn.value(term)
+ }
+ searchList.value = arr
+ if(searchList.value.length==0){
+ showNoResultItemTemplate.value=true
+ }else{
+ showNoResultItemTemplate.value=false
+ }
+ }
+ const recentlyFocus = (latestSource:Array) => {
+ if(latestSource) {
+ searchList.value = latestSource
+ }
+ }
+ return {
+ handleSearch,
+ recentlyFocus,
+ searchList,
+ showNoResultItemTemplate
+ }
+}
diff --git a/packages/devui-vue/devui/auto-complete/src/composables/use-select-handle.ts b/packages/devui-vue/devui/auto-complete/src/composables/use-select-handle.ts
new file mode 100644
index 0000000000..8261410c70
--- /dev/null
+++ b/packages/devui-vue/devui/auto-complete/src/composables/use-select-handle.ts
@@ -0,0 +1,25 @@
+import { ref, Ref, SetupContext } from 'vue';
+import { DefaultFuncType,FormatterType,HandleSearch } from '../auto-complete-types';
+
+export default function useSelectHandle(ctx: SetupContext,searchList: Ref>, selectValue: Ref, handleSearch: HandleSearch,formatter: Ref,handleClose:DefaultFuncType): any {
+ const selectedIndex = ref(0)
+ const getListIndex = (item: string) => {
+ if (searchList.value.length == 0) {
+ return 0
+ }
+ const ind = searchList.value.indexOf(item)
+ return ind == -1 ? 0 : ind
+ }
+ const selectOptionClick = async(item: any) => {
+ const cur = formatter.value(item)
+ ctx.emit('update:modelValue', cur)
+ handleClose()
+ await handleSearch(cur)
+ selectedIndex.value = getListIndex(cur)
+ selectValue.value && selectValue.value()
+ }
+ return {
+ selectedIndex,
+ selectOptionClick
+ }
+}
\ No newline at end of file
diff --git a/packages/devui-vue/docs/components/auto-complete/index.md b/packages/devui-vue/docs/components/auto-complete/index.md
new file mode 100644
index 0000000000..496d91a09f
--- /dev/null
+++ b/packages/devui-vue/docs/components/auto-complete/index.md
@@ -0,0 +1,508 @@
+# AutoComplete 自动补全
+
+联想用户可能需要的输入结果。
+
+### 何时使用
+
+当需要根据用户输入的部分字符推断出他可能想要输入的内容时。
+
+
+### 基本用法
+通过 source 设置自动完成的数据源。
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+### 设置禁用
+通过 disabled 设置是否禁用。
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+ {{ isDisabled ? 'Enable AutoComplete' : 'Disable AutoComplete' }}
+
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### 自定义数据匹配方法
+通过 searchFn 自定义数据的匹配方法和返回的数据格式。
+:::demo
+
+```vue
+
+
+
+
+ {{`searching: ${slotProps}`}}
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### 自定义模板展示
+通过 itemTemplate、noResultItemTemplate 自定义下拉框和无匹配提示。
+:::demo
+
+```vue
+
+
+
+
+ 第{{slotProps.index}}项: {{slotProps.item}}
+
+
+
+
+ {{`没有匹配项: ${slotProps}`}}
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+### 最近输入
+
+通过 latestSource 设置最近输入。
+
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+
+### 懒加载
+enableLazyLoad 开启懒加载
+
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+### d-auto-complete
+
+d-auto-complete 参数
+
+| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 |
+| :--------------------: | :-------------------------------------------------: | :----------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------- | ---------- |
+| source | `Array` | -- | 必选,有 searchFn 的情况下可以不必选 | [基本用法](#基本用法) |
+| allowEmptyValueSearch | `boolean` | false | 可选,在绑定的输入框 value 为空时,是否进行搜索提示操作 | [基本用法](#基本用法) |
+| appendToBody | `boolean` | false | 可选,下拉弹出是否 append to body | [基本用法](#基本用法) |
+| appendToBodyDirections | `Object as PropType` | `{originX: 'left',originY: 'bottom',overlayX: 'left',overlayY: 'top',}` | 可选,指定下拉框与输入框的相对位置,ConnectionPosition 请参考 Overlay | [基本用法](#基本用法) |
+| disabled | `boolean` | false | 可选,是否禁用指令 | [设置禁用](#设置禁用) |
+| delay | `number` | 300 | 可选,只有在 delay 时间经过后并且未输入新值,才做搜索查询(`ms`) | [基本用法](#基本用法) |
+| disabledKey | `string` | -- | 可选,禁用单个选项,当传入资源 source 选项类型为对象,比如设置为'disabled',则当对象的 disable 属性为 true 时,比如{ label: xxx, disabled: true },该选项将禁用 | [自定义数据匹配方法](#自定义数据匹配方法) |
+| itemTemplate | `slot` | -- | 可选,自定义展示模板。slotProps:{ index: 下标索引, item: 当前项内容 }。 | [自定义模板展示](#自定义模板展示) |
+| noResultItemTemplate | `slot` | -- | 可选,没有匹配项的展示结果。slotProps:输入内容。 | [自定义模板展示](#自定义模板展示) |
+| formatter | `(item: any) => string` | [`defaultFormatter`](#defaultformatter) | 可选,格式化函数 | [自定义数据匹配方法](#自定义数据匹配方法) |
+| isSearching | `boolean` | false | 可选,是否在搜索中,用于控制 searchingTemplate 是否显示 | [自定义数据匹配方法](#自定义数据匹配方法) |
+| searchingTemplate | `slot` | -- | 可选,自定义搜索中显示模板。slotProps:输入内容。 | [自定义数据匹配方法](#自定义数据匹配方法) |
+| sceneType | `string` | -- | 可选,值为 'select'、'suggest' | [启用懒加载](demo#auto-lazy-load) |
+| searchFn | `(term: string) => Array` | [`defaultSearchFn`](#defaultsearchfn) | 可选,自定义搜索过滤 | [自定义数据匹配方法](#自定义数据匹配方法) |
+| tipsText | `string` | '最近输入' | 可选,提示文字 | [设置禁用](demo#auto-disable) |
+| latestSource | `Array` | -- | 可选, 最近输入 | [最近输入](demo#auto-latest) |
+| valueParser | `(item: any) => any` | [`defaultValueParse`](#defaultvalueparse) | 可选, 对选中后数据进行处理 | [启用懒加载](demo#auto-lazy-load) |
+| enableLazyLoad | `boolean` | false | 可选,是否允许懒加载 | [启用懒加载](demo#auto-lazy-load) |
+| dAutoCompleteWidth | `number` | -- | 可选,调整宽度(`px`) |[基本用法](#基本用法)
+| showAnimation | `boolean` | true | 可选,是否开启动画 | | ✔ | | |
+
+d-auto-complete 事件
+
+| 参数 | 类型 | 说明 | 跳转 Demo |
+| :-----------------: | :----------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------- |
+| loadMore | `EventEmitter>` | 懒加载触发事件,配合`enableLazyLoad`使用,使用`$event.loadFinish()`关闭 loading 状态,其中\$event 为 AutoCompletePopupComponent 的实例 | [启用懒加载](demo#auto-lazy-load) |
+| selectValue | `EventEmitter` | 可选,选择选项之后的回调函数 | [基本用法](#基本用法) |
+| transInputFocusEmit | `EventEmitter` | 可选,Input focus 时回调函数 | [基本用法](#基本用法) |
+
+
+# 接口 & 类型定义
+
+### defaultSearchFn
+
+```ts
+defaultSearchFn = (term) => {
+ return source.forEach((item)=>{
+ let cur = formatter(item)
+ cur = cur.toLowerCase()
+ if(cur.startsWith(term)){
+ arr.push(item)
+ }
+ })
+ };
+```
+term 为输入的关键字。
+
+
+### defaultFormatter
+
+```ts
+defaultFormatter = (item) => (item ? item.label || item.toString() : '');
+```
+item 为数据项。
+
+
+### defaultValueParse
+
+```ts
+defaultValueParse = (item) => item;
+```
+item 为数据项。
diff --git a/packages/devui-vue/docs/en-US/components/auto-complete/api-en.md b/packages/devui-vue/docs/en-US/components/auto-complete/api-en.md
new file mode 100644
index 0000000000..ad5f795303
--- /dev/null
+++ b/packages/devui-vue/docs/en-US/components/auto-complete/api-en.md
@@ -0,0 +1,508 @@
+# AutoComplete
+
+Guess what users may need when entering.
+
+### When To Use
+
+When you need to deduce the content that a user may want to enter according to some characters entered by the user.
+
+
+### Basic usage
+Set source to the data source that is automatically completed.
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+### Disabled
+You can set the disabled parameter to disable it in the text box and disable the options in the drop-down list box by using the disabledKey parameter.
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+ {{ isDisabled ? 'Enable AutoComplete' : 'Disable AutoComplete' }}
+
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### Customized data matching method
+You can use searchFn to customize the data matching method and the returned data format.
+:::demo
+
+```vue
+
+
+
+
+ {{`searching: ${slotProps}`}}
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### Customized template display
+Use itemTemplate and noResultItemTemplate to customize the drop-down list box and display no matching message.
+:::demo
+
+```vue
+
+
+
+
+ No.{{slotProps.index}}: {{slotProps.item}}
+
+
+
+
+ {{`No any results match : ${slotProps}`}}
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+### Latest input
+
+Set latestSource to the latest input.
+
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+
+:::
+
+### Enable lazy load
+
+enableLazyLoad: enables lazy loading.
+
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+:::
+
+
+
+### d-auto-complete
+
+d-auto-complete Parameter
+
+| Parameter | Type | Default | Description | Jump to Demo | Global Config |
+| :--------------------: | :-------------------------------------------------: | :----------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------- | ---------- |
+| source | `Array` | -- | Required. This parameter is optional if searchFn is specified. | [Basic usage](#Basic usage) |
+| allowEmptyValueSearch | `boolean` | false | Optional. indicates whether to display a search message when the bound text box value is empty. | [Basic usage](#Basic usage) |
+| appendToBody | `boolean` | false | Optional. Whether to append to body is displayed in the drop-down list box. | [Basic usage](#Basic usage) |
+| appendToBodyDirections | `Object as PropType` | `{originX: 'left',originY: 'bottom',overlayX: 'left',overlayY: 'top',}` | Optional. Specify the relative position of the drop-down box and the input box. for details about ConnectionPosition, see Overlay | [Basic usage](#Basic usage) |
+| disabled | `boolean` | false | Optional. Indicating whether to disable commands. | [Disabled](#Disabled) |
+| delay | `number` | 300 | Optional. The search is performed only after the delay time elapses and a new value is entered. (ms) | [Basic usage](#Basic usage) |
+| disabledKey | `string` | -- | Optional. Disable a single option. If the input resource source option type is an object, for example, disabled, and the disable attribute of the object is true, for example, {label: xxx, disabled: true}, this option will be disabled | [Customized data matching method](#Customized data matching method) |
+| itemTemplate | `slot` | -- | Optional. Customized display template | [Customized template display](#Customized template display) |
+| noResultItemTemplate | `slot` | -- | Optional. No matching item is displayed. | [Customized template display](#Customized template display) |
+| formatter | `(item: any) => string` | [`defaultFormatter`](#defaultformatter) | Optional. Formatting function | [Customized data matching method](#Customized data matching method) |
+| isSearching | `boolean` | false | Optional. indicating whether the search template is displayed. | [Customized data matching method](#Customized data matching method) |
+| searchingTemplate | `slot` | -- | Optional. The template is displayed in customized search. | [Customized data matching method](#Customized data matching method) |
+| sceneType | `string` | -- | Optional. The value can be select or suggestion. | [Enable lazy load](demo#auto-lazy-load) |
+| searchFn | `(term: string) => Array` | [`defaultSearchFn`](#defaultsearchfn) | Optional. Customized search filtering | [Customized data matching method](#Customized data matching method) |
+| tipsText | `string` | 'Latest input' | Optional. prompt text | [Disabled](demo#auto-disable) |
+| latestSource | `Array` | -- | Optional. Latest input | [Latest input](demo#auto-latest) |
+| valueParser | `(item: any) => any` | [`defaultValueParse`](#defaultvalueparse) | (optional) Process selected data | [Enable lazy load](demo#auto-lazy-load) |
+| enableLazyLoad | `boolean` | false | Optional. Whether lazy loading is allowed | [Enable lazy load](demo#auto-lazy-load) |
+| dAutoCompleteWidth | `number` | -- | Optional. Adjust the width (px) |[Basic usage](#Basic usage)
+| showAnimation | `boolean` | true | optional. Whether to enable animation. | | ✔ | | |
+
+dAutoComplete Event
+
+| Parameter | Type | Description | Jump to Demo |
+| :-----------------: | :----------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------- |
+| loadMore | `EventEmitter>` | : optional. It is a lazy loading trigger event. It is used together with enableLazyLoad. `$event.loadFinish()` is used to disable the loading status. $event is the instance of the pop-up component AutoCompletePopupComponent | [Enable lazy load](demo#auto-lazy-load) |
+| selectValue | `EventEmitter` | (optional), callback function after selecting an option数 | [Basic usage](#Basic usage) |
+| transInputFocusEmit | `EventEmitter` | (optional). Callback function for input focus | [Basic usage](#Basic usage) |
+
+
+# Interface & Type Definition
+
+### defaultSearchFn
+
+```ts
+defaultSearchFn = (term) => {
+ return source.forEach((item)=>{
+ let cur = formatter(item)
+ cur = cur.toLowerCase()
+ if(cur.startsWith(term)){
+ arr.push(item)
+ }
+ })
+ };
+```
+term indicates the entered keyword.
+
+
+### defaultFormatter
+
+```ts
+defaultFormatter = (item) => (item ? item.label || item.toString() : '');
+```
+item indicates a data item.
+
+
+### defaultValueParse
+
+```ts
+defaultValueParse = (item) => item;
+```
+item indicates a data item.