fix(components): virtualized selector optimize (#3160)

1. limit the maximum width to prevent content overflow
2. hover the last option after closing the panel in multiple mode
3. fixed the incorrect style when disabled
4. optimized tag style
This commit is contained in:
msidolphin 2021-09-01 13:14:17 +08:00 committed by GitHub
parent 2431c6d44d
commit 7556a1b2d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 181 additions and 86 deletions

View File

@ -979,4 +979,54 @@ describe('Select', () => {
await nextTick()
expect(vm.value).toEqual([6])
})
it('multiple select when content overflow', async () => {
const wrapper = createSelect({
data () {
return {
options: [{
value: '选项1',
label: '黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕黄金糕',
}, {
value: '选项2',
label: '双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶双皮奶',
}, {
value: '选项3',
label: '蚵仔煎蚵仔煎蚵仔煎蚵仔煎蚵仔煎蚵仔煎',
}, {
value: '选项4',
label: '龙须面',
}, {
value: '选项5',
label: '北京烤鸭',
}],
}
},
})
const select = wrapper.findComponent(Select)
const selectVm = select.vm as any
const selectDom = wrapper.find('.el-select-v2__wrapper').element
const selectRect = {
height: 40,
width: 221,
x:44,
y:8,
top:8,
}
const mockSelectWidth = jest.spyOn(selectDom, 'getBoundingClientRect').mockReturnValue(selectRect as DOMRect)
selectVm.handleResize()
const options = getOptions()
options[0].click()
await nextTick()
options[1].click()
await nextTick()
options[2].click()
await nextTick()
const tagWrappers = wrapper.findAll('.el-select-v2__tags-text')
for(let i = 0;i < tagWrappers.length;i++) {
const tagWrapperDom = tagWrappers[i].element
expect(parseInt(tagWrapperDom.style.maxWidth) === selectRect.width - 42).toBe(true)
}
mockSelectWidth.mockRestore()
})
})

View File

@ -52,7 +52,9 @@
>
<span
class="el-select-v2__tags-text"
:style="{ maxWidth: states.inputWidth - 123 + 'px' }"
:style="{
maxWidth: `${tagMaxWidth}px`
}"
>{{ states.cachedOptions[0].label }}</span>
</el-tag>
<el-tag
@ -62,7 +64,12 @@
type="info"
disable-transitions
>
<span class="el-select-v2__tags-text">+ {{ modelValue.length - 1 }}</span>
<span
class="el-select-v2__tags-text"
:style="{
maxWidth: `${tagMaxWidth}px`
}"
>+ {{ modelValue.length - 1 }}</span>
</el-tag>
</div>
</template>
@ -81,7 +88,12 @@
disable-transitions
@close="deleteTag($event, selected)"
>
{{ getLabel(selected) }}
<span
class="el-select-v2__tags-text"
:style="{
maxWidth: `${tagMaxWidth}px`
}"
>{{ getLabel(selected) }}</span>
</el-tag>
</div>
</template>

View File

@ -38,6 +38,10 @@ import { useInput } from './useInput'
const DEFAULT_INPUT_PLACEHOLDER = ''
const MINIMUM_INPUT_WIDTH = 11
const TAG_BASE_WIDTH = {
small: 42,
mini: 33,
}
const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
@ -63,7 +67,7 @@ const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
isSilentBlur: false,
isComposing: false,
inputLength: 20,
inputWidth: 240,
selectWidth: 200,
initialInputHeight: 0,
previousQuery: null,
previousValue: '',
@ -165,6 +169,14 @@ const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
const collapseTagSize = computed(() => ['small', 'mini'].indexOf(selectSize.value) > -1 ? 'mini' : 'small')
const tagMaxWidth = computed(() => {
const select = selectionRef.value
const size = collapseTagSize.value
const paddingLeft = select ? parseInt(getComputedStyle(select).paddingLeft) : 0
const paddingRight = select ? parseInt(getComputedStyle(select).paddingRight) : 0
return states.selectWidth - paddingRight - paddingLeft - TAG_BASE_WIDTH[size]
})
const calculatePopperSize = () => {
popperSize.value = selectRef.value?.getBoundingClientRect?.()?.width || 200
}
@ -203,8 +215,9 @@ const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
// the index with current value in options
const indexRef = computed<number>(() => {
if (props.multiple) {
const len = (props.modelValue as []).length
if ((props.modelValue as Array<any>).length > 0) {
return filteredOptions.value.findIndex(o => o.value === props.modelValue[0])
return filteredOptions.value.findIndex(o => o.value === props.modelValue[len - 1])
}
} else {
if (props.modelValue) {
@ -324,12 +337,15 @@ const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
resetInputWidth()
calculatePopperSize()
popper.value?.update?.()
if (props.multiple) resetInputHeight()
if (props.multiple) {
return resetInputHeight()
}
}
const resetInputWidth = () => {
if (inputRef.value) {
states.inputWidth = inputRef.value.getBoundingClientRect().width
const select = selectionRef.value
if (select) {
states.selectWidth = select.getBoundingClientRect().width
}
}
@ -678,6 +694,7 @@ const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
selectSize,
showClearBtn,
states,
tagMaxWidth,
// refs items exports
calculatorRef,
@ -704,6 +721,7 @@ const useSelect = (props: ExtractPropTypes<typeof SelectProps>, emit) => {
handleEsc,
handleFocus,
handleMenuEnter,
handleResize,
toggleMenu,
scrollTo: scrollToItem,
onInput,

View File

@ -775,6 +775,17 @@ $--tag: map.merge(
$--tag-color: () !default;
$--tag-height: () !default;
$--tag-height: map.merge(
(
'default': 32px,
'medium': 28px,
'small': 24px,
'mini': 20px,
),
$--tag-height
);
@each $type in $--types {
$--tag-color: map.merge(
(

View File

@ -52,7 +52,7 @@ $--input-inline-start: 15px !default;
border-color: var(--el-select-disabled-border);
&:hover {
border-color: inherit;
border-color: var(--el-select-disabled-border);
}
&.is-focus {
@ -98,6 +98,13 @@ $--input-inline-start: 15px !default;
}
}
.#{$namespace}-select-v2__tags-text {
text-overflow: ellipsis;
display: inline-block;
overflow-x: hidden;
vertical-align: bottom;
}
@include e(empty) {
padding: 10px 0;
margin: 0;
@ -314,7 +321,6 @@ $--input-inline-start: 15px !default;
.#{$namespace}-icon-close {
background-color: var(--el-text-color-placeholder);
right: -7px;
top: 0;
color: var(--el-color-white);
&:hover {

View File

@ -84,9 +84,9 @@
@include b(tag) {
@include genTheme(10%, 20%, 100%, 100%);
display: inline-block;
height: 32px;
height: map.get($--tag-height, 'default');
padding: var(--el-tag-padding);
line-height: 30px;
line-height: map.get($--tag-height, 'default') - 2px;
font-size: var(--el-tag-font-size);
border-width: 1px;
border-style: solid;
@ -120,30 +120,28 @@
@include genTheme(0, 40%, 100%, 100%);
}
@include m(medium) {
height: 28px;
line-height: 26px;
@each $size in (medium, small, mini) {
@include m($size) {
height: map.get($--tag-height, $size);
line-height: map.get($--tag-height, $size) - 2px;
}
}
@include m(medium) {
.#{$namespace}-icon-close {
transform: scale(0.8);
}
}
@include m(small) {
height: 24px;
padding: 0 8px;
line-height: 22px;
.#{$namespace}-icon-close {
transform: scale(0.8);
}
}
@include m(mini) {
height: 20px;
padding: 0 5px;
line-height: 19px;
.#{$namespace}-icon-close {
margin-left: -3px;
transform: scale(0.7);

View File

@ -20,7 +20,7 @@ The simplest selector
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
/>
</template>
@ -53,7 +53,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -86,7 +86,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
collapse-tags
/>
@ -122,7 +122,7 @@ When the options are overwhelmingly too many, you can use `filterable` option to
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -157,7 +157,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
/>
<el-select-v2
@ -166,7 +166,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
multiple
/>
</template>
@ -203,7 +203,7 @@ We can group option as we wanted, as long as the data satisfies the pattern.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -245,7 +245,7 @@ We can define our own template for rendering the option in the popup.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
>
<template #default="{item}">
@ -287,7 +287,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
clearable
/>
@ -295,7 +295,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
clearable
/>
</template>
@ -328,7 +328,7 @@ Create and select new items that are not included in select options
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
allow-create
filterable
multiple
@ -338,7 +338,7 @@ Create and select new items that are not included in select options
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
allow-create
filterable
clearable
@ -372,7 +372,7 @@ Enter keywords and search data from server.
<template>
<el-select-v2
v-model="value"
style="width:200px"
style="width: 240px"
multiple
size="medium"
filterable

View File

@ -20,7 +20,7 @@ The simplest selector
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
/>
</template>
@ -53,7 +53,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -86,7 +86,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
collapse-tags
/>
@ -122,7 +122,7 @@ When the options are overwhelmingly too many, you can use `filterable` option to
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -157,7 +157,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
/>
<el-select-v2
@ -166,7 +166,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
multiple
/>
</template>
@ -203,7 +203,7 @@ We can group option as we wanted, as long as the data satisfies the pattern.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -245,7 +245,7 @@ We can define our own template for rendering the option in the popup.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
>
<template #default="{item}">
@ -287,7 +287,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
clearable
/>
@ -295,7 +295,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
clearable
/>
</template>
@ -329,7 +329,7 @@ Crear y seleccionar nuevos items que no están incluidas en las opciones de sele
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
allow-create
filterable
multiple
@ -339,7 +339,7 @@ Crear y seleccionar nuevos items que no están incluidas en las opciones de sele
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
allow-create
filterable
clearable
@ -373,7 +373,7 @@ Introduzca palabras y datos para buscar desde el servidor.
<template>
<el-select-v2
v-model="value"
style="width:200px"
style="width: 240px"
multiple
size="medium"
filterable

View File

@ -20,7 +20,7 @@ The simplest selector
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
/>
</template>
@ -53,7 +53,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -86,7 +86,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
collapse-tags
/>
@ -122,7 +122,7 @@ When the options are overwhelmingly too many, you can use `filterable` option to
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -157,7 +157,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
/>
<el-select-v2
@ -166,7 +166,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
multiple
/>
</template>
@ -203,7 +203,7 @@ We can group option as we wanted, as long as the data satisfies the pattern.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -245,7 +245,7 @@ We can define our own template for rendering the option in the popup.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
>
<template #default="{item}">
@ -287,7 +287,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
clearable
/>
@ -295,7 +295,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
clearable
/>
</template>
@ -330,7 +330,7 @@ Vous pouvez entrer des choix dans le champ de sélection qui ne sont pas incluse
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
allow-create
filterable
multiple
@ -340,7 +340,7 @@ Vous pouvez entrer des choix dans le champ de sélection qui ne sont pas incluse
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
allow-create
filterable
clearable
@ -374,7 +374,7 @@ Vous pouvez aller chercher les options sur le serveur de manière dynamique.
<template>
<el-select-v2
v-model="value"
style="width:200px"
style="width: 240px"
multiple
size="medium"
filterable

View File

@ -20,7 +20,7 @@ The simplest selector
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
/>
</template>
@ -53,7 +53,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -86,7 +86,7 @@ The basic multi-select selector with tags
v-model="value"
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
collapse-tags
/>
@ -122,7 +122,7 @@ When the options are overwhelmingly too many, you can use `filterable` option to
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -157,7 +157,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
/>
<el-select-v2
@ -166,7 +166,7 @@ You can choose to disable selector itself or the option.
filterable
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
multiple
/>
</template>
@ -203,7 +203,7 @@ We can group option as we wanted, as long as the data satisfies the pattern.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -245,7 +245,7 @@ We can define our own template for rendering the option in the popup.
filterable
:options="options"
placeholder="Please select"
style="width: 200px;"
style="width: 240px;"
multiple
>
<template #default="{item}">
@ -287,7 +287,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
clearable
/>
@ -295,7 +295,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
clearable
/>
</template>
@ -328,7 +328,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value1"
:options="options"
placeholder="Please select"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
allow-create
filterable
multiple
@ -338,7 +338,7 @@ We can clear all the selected options at once, also applicable for single select
v-model="value2"
:options="options"
placeholder="Please select"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
allow-create
filterable
clearable
@ -372,7 +372,7 @@ We can clear all the selected options at once, also applicable for single select
<template>
<el-select-v2
v-model="value"
style="width:200px"
style="width: 240px"
multiple
size="medium"
filterable

View File

@ -20,7 +20,7 @@
v-model="value"
:options="options"
placeholder="请选择"
style="width: 200px;"
style="width: 240px;"
/>
</template>
@ -53,7 +53,7 @@
v-model="value"
:options="options"
placeholder="请选择"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -86,7 +86,7 @@
v-model="value"
:options="options"
placeholder="请选择"
style="width: 200px;"
style="width: 240px;"
multiple
collapse-tags
/>
@ -122,7 +122,7 @@
filterable
:options="options"
placeholder="请选择"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -157,7 +157,7 @@
filterable
:options="options"
placeholder="请选择"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
/>
<el-select-v2
@ -166,7 +166,7 @@
filterable
:options="options"
placeholder="请选择"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
multiple
/>
</template>
@ -203,7 +203,7 @@
filterable
:options="options"
placeholder="请选择"
style="width: 200px;"
style="width: 240px;"
multiple
/>
</template>
@ -246,7 +246,7 @@
filterable
:options="options"
placeholder="请选择"
style="width: 200px;"
style="width: 240px;"
multiple
>
<template #default="{item}">
@ -287,7 +287,7 @@
v-model="value1"
:options="options"
placeholder="请选择"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
multiple
clearable
/>
@ -295,7 +295,7 @@
v-model="value2"
:options="options"
placeholder="请选择"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
clearable
/>
</template>
@ -329,7 +329,7 @@
v-model="value1"
:options="options"
placeholder="请选择"
style="width: 200px; margin-right: 16px; vertical-align: middle;"
style="width: 240px; margin-right: 16px; vertical-align: middle;"
allow-create
filterable
multiple
@ -339,7 +339,7 @@
v-model="value2"
:options="options"
placeholder="请选择"
style="width: 200px; vertical-align: middle;"
style="width: 240px; vertical-align: middle;"
allow-create
filterable
clearable
@ -372,7 +372,7 @@
<template>
<el-select-v2
v-model="value"
style="width:200px"
style="width: 240px"
multiple
size="medium"
filterable