mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(autocomplete): popper usage (#429)
* fix(autocomplete): dropdownWidth * fix: el-popper usage * test: change test file * fix: remove storybook doc dir * test: sleep time
This commit is contained in:
@@ -1,90 +1,93 @@
|
||||
<template>
|
||||
<div
|
||||
v-clickoutside="close"
|
||||
class="el-autocomplete"
|
||||
role="combobox"
|
||||
aria-haspopup="listbox"
|
||||
:aria-expanded="suggestionVisible"
|
||||
:aria-owns="id"
|
||||
<el-popper
|
||||
ref="popper"
|
||||
v-model:visible="suggestionVisible"
|
||||
:placement="placement"
|
||||
:popper-class="popperClass"
|
||||
:append-to-body="popperAppendToBody"
|
||||
:offset="6"
|
||||
pure
|
||||
manual-mode
|
||||
effect="light"
|
||||
trigger="click"
|
||||
>
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-bind="$attrs"
|
||||
:model-value="modelValue"
|
||||
@input="handleInput"
|
||||
@change="handleChange"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
@clear="handleClear"
|
||||
@keydown.up.prevent="highlight(highlightedIndex - 1)"
|
||||
@keydown.down.prevent="highlight(highlightedIndex + 1)"
|
||||
@keydown.enter.prevent="handleKeyEnter"
|
||||
@keydown.tab.prevent="close"
|
||||
>
|
||||
<template v-if="$slots.prepend" #prepend>
|
||||
<slot name="prepend"></slot>
|
||||
</template>
|
||||
<template v-if="$slots.append" #append>
|
||||
<slot name="append"></slot>
|
||||
</template>
|
||||
<template v-if="$slots.prefix" #prefix>
|
||||
<slot name="prefix"></slot>
|
||||
</template>
|
||||
<template v-if="$slots.suffix" #suffix>
|
||||
<slot name="suffix"></slot>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-popper
|
||||
class="el-autocomplete-suggestion"
|
||||
:placement="placement"
|
||||
:popper-class="popperClass"
|
||||
:append-to-body="popperAppendToBody"
|
||||
:visible="suggestionVisible"
|
||||
:show-arrow="false"
|
||||
pure
|
||||
effect="light"
|
||||
trigger="click"
|
||||
>
|
||||
<template #trigger>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div
|
||||
v-show="suggestionVisible"
|
||||
ref="regionRef"
|
||||
:class="{ 'is-loading': suggestionLoading }"
|
||||
style="outline: none"
|
||||
role="region"
|
||||
<template #trigger>
|
||||
<div
|
||||
v-clickoutside="close"
|
||||
class="el-autocomplete"
|
||||
role="combobox"
|
||||
aria-haspopup="listbox"
|
||||
:aria-expanded="suggestionVisible"
|
||||
:aria-owns="id"
|
||||
>
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-bind="$attrs"
|
||||
:model-value="modelValue"
|
||||
@input="handleInput"
|
||||
@change="handleChange"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
@clear="handleClear"
|
||||
@keydown.up.prevent="highlight(highlightedIndex - 1)"
|
||||
@keydown.down.prevent="highlight(highlightedIndex + 1)"
|
||||
@keydown.enter.prevent="handleKeyEnter"
|
||||
@keydown.tab.prevent="close"
|
||||
>
|
||||
<template v-if="$slots.prepend" #prepend>
|
||||
<slot name="prepend"></slot>
|
||||
</template>
|
||||
<template v-if="$slots.append" #append>
|
||||
<slot name="append"></slot>
|
||||
</template>
|
||||
<template v-if="$slots.prefix" #prefix>
|
||||
<slot name="prefix"></slot>
|
||||
</template>
|
||||
<template v-if="$slots.suffix" #suffix>
|
||||
<slot name="suffix"></slot>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<transition name="el-zoom-in-top" @after-leave="doDestroy">
|
||||
<div
|
||||
v-show="suggestionVisible"
|
||||
ref="regionRef"
|
||||
:class="['el-autocomplete-suggestion', suggestionLoading && 'is-loading']"
|
||||
:style="{ width: dropdownWidth, outline: 'none' }"
|
||||
role="region"
|
||||
>
|
||||
<el-scrollbar
|
||||
tag="ul"
|
||||
wrap-class="el-autocomplete-suggestion__wrap"
|
||||
view-class="el-autocomplete-suggestion__list"
|
||||
>
|
||||
<el-scrollbar
|
||||
tag="ul"
|
||||
wrap-class="el-autocomplete-suggestion__wrap"
|
||||
view-class="el-autocomplete-suggestion__list"
|
||||
>
|
||||
<li v-if="suggestionLoading">
|
||||
<i class="el-icon-loading"></i>
|
||||
<li v-if="suggestionLoading">
|
||||
<i class="el-icon-loading"></i>
|
||||
</li>
|
||||
<template v-else>
|
||||
<li
|
||||
v-for="(item, index) in suggestions"
|
||||
:id="`${id}-item-${index}`"
|
||||
:key="index"
|
||||
:class="{'highlighted': highlightedIndex === index}"
|
||||
role="option"
|
||||
:aria-selected="highlightedIndex === index"
|
||||
@click="select(item)"
|
||||
>
|
||||
<slot :item="item">{{ item[valueKey] }}</slot>
|
||||
</li>
|
||||
<template v-else>
|
||||
<li
|
||||
v-for="(item, index) in suggestions"
|
||||
:id="`${id}-item-${index}`"
|
||||
:key="index"
|
||||
:class="{'highlighted': highlightedIndex === index}"
|
||||
role="option"
|
||||
:aria-selected="highlightedIndex === index"
|
||||
@click="select(item)"
|
||||
>
|
||||
<slot :item="item">{{ item[valueKey] }}</slot>
|
||||
</li>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
</el-popper>
|
||||
</div>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
</el-popper>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, onMounted, nextTick, PropType } from 'vue'
|
||||
import { defineComponent, ref, computed, onMounted, nextTick, PropType, watch } from 'vue'
|
||||
import { NOOP } from '@vue/shared'
|
||||
import debounce from 'lodash/debounce'
|
||||
import { ClickOutside } from '@element-plus/directives'
|
||||
@@ -159,11 +162,13 @@ export default defineComponent({
|
||||
setup(props, ctx) {
|
||||
const suggestions = ref([])
|
||||
const highlightedIndex = ref(-1)
|
||||
const dropdownWidth = ref('')
|
||||
const activated = ref(false)
|
||||
const suggestionDisabled = ref(false)
|
||||
const loading = ref(false)
|
||||
const inputRef = ref(null)
|
||||
const regionRef = ref(null)
|
||||
const popper = ref(null)
|
||||
|
||||
const id = computed(() => {
|
||||
return `el-autocomplete-${generateId()}`
|
||||
@@ -176,6 +181,10 @@ export default defineComponent({
|
||||
return !props.hideLoading && loading.value
|
||||
})
|
||||
|
||||
watch(suggestionVisible, () => {
|
||||
dropdownWidth.value = `${inputRef.value.$el.offsetWidth}px`
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
inputRef.value.inputOrTextarea.setAttribute('role', 'textbox')
|
||||
inputRef.value.inputOrTextarea.setAttribute('aria-autocomplete', 'list')
|
||||
@@ -288,15 +297,20 @@ export default defineComponent({
|
||||
highlightedIndex.value = index
|
||||
inputRef.value.inputOrTextarea.setAttribute('aria-activedescendant', `${id.value}-item-${highlightedIndex.value}`)
|
||||
}
|
||||
const doDestroy = () => {
|
||||
popper.value.doDestroy()
|
||||
}
|
||||
|
||||
return {
|
||||
suggestions,
|
||||
highlightedIndex,
|
||||
dropdownWidth,
|
||||
activated,
|
||||
suggestionDisabled,
|
||||
loading,
|
||||
inputRef,
|
||||
regionRef,
|
||||
popper,
|
||||
|
||||
id,
|
||||
suggestionVisible,
|
||||
@@ -313,6 +327,7 @@ export default defineComponent({
|
||||
focus,
|
||||
select,
|
||||
highlight,
|
||||
doDestroy,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user