Skip to content

Commit

Permalink
fix(select): ensure sync init values and labels
Browse files Browse the repository at this point in the history
fix #36
  • Loading branch information
qmhc committed Jun 14, 2022
1 parent 237f3cf commit ae04af0
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 133 deletions.
163 changes: 54 additions & 109 deletions components/select/select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@
</div>
<div :class="`${prefixCls}__control`">
<slot name="control">
<template v-if="props.multiple && Array.isArray(currentValue)">
<template v-if="props.multiple">
<Tag
v-for="(item, index) in currentValue"
v-for="(item, index) in currentValues"
:key="index"
:class="`${prefixCls}__tag`"
closable
@click.stop="handleClick"
@close="handleSelect(item, currentLabel[index])"
@close="handleSelect(item, currentLabels[index])"
>
{{ currentLabel[index] }}
{{ currentLabels[index] }}
</Tag>
</template>
<template v-else>
{{ currentLabel }}
{{ currentLabels[0] }}
</template>
<span
v-if="(props.placeholder ?? locale.placeholder) && !hasValue"
Expand Down Expand Up @@ -95,7 +95,7 @@
<slot
:option="item"
:index="index"
:selected="item.value === currentValue"
:selected="isSelected(item.value)"
:handle-select="handleSelect"
>
<Option
Expand All @@ -105,14 +105,14 @@
:divided="item.divided"
:no-title="item.noTitle"
:hitting="item.hitting"
:select="item.value === currentValue"
:select="isSelected(item.value)"
@select="handleSelect"
>
<span :class="`${prefixCls}__label`">
{{ item.label || item.value }}
</span>
<transition v-if="props.optionCheck" name="vxp-fade" appear>
<Icon v-if="item.value === currentValue" :class="`${prefixCls}__check`">
<Icon v-if="isSelected(item.value)" :class="`${prefixCls}__check`">
<Check></Check>
</Icon>
</transition>
Expand Down Expand Up @@ -259,9 +259,8 @@ export default defineComponent({
const prefix = 'vxp-select'
const currentVisible = ref(props.visible)
// const focused = ref(false)
const currentLabel = ref<string | string[]>(props.multiple ? [] : '')
const currentValue = ref<typeof props.value>(props.multiple ? [] : '')
const currentLabels = ref<string[]>([])
const currentValues = ref<(string | number)[]>([])
const placement = toRef(props, 'placement')
const transfer = toRef(props, 'transfer')
const listHeight = ref<string | undefined>(undefined)
Expand Down Expand Up @@ -328,29 +327,13 @@ export default defineComponent({
[`${baseCls}--has-suffix`]: !props.noSuffix
}
})
const hasValue = computed(() => {
return Array.isArray(currentValue.value)
? currentValue.value.length > 0
: currentValue.value || currentValue.value === 0
})
const hasValue = computed(() => !isNull(currentValues.value[0]))
const hasPrefix = computed(() => {
return !!(slots.prefix || props.prefix)
})
const optionStates = computed(() => {
return Array.from(optionMap.value.values())
})
// const controlStyle = computed(() => {
// return {
// paddingRight: props.noSuffix ? '' : '2em',
// paddingLeft: hasPrefix.value ? '2em' : ''
// }
// })
// const placeholderStyle = computed(() => {
// return {
// right: props.noSuffix ? '' : '2em',
// left: hasPrefix.value ? '2em' : ''
// }
// })
const visibleOptions = computed(() => {
return optionStates.value.filter(state => !state.hidden)
})
Expand Down Expand Up @@ -379,80 +362,42 @@ export default defineComponent({
watch(
() => props.value,
value => {
currentValue.value = props.multiple && !Array.isArray(value) ? [value] : value
syncCurrentLabel()
initValueAndLabel(value)
},
{ immediate: true }
)
watch(() => visibleOptions.value.length, computeListHeight)
watch(
() => props.multiple,
value => {
if (value) {
if (!Array.isArray(currentValue.value)) {
currentValue.value = [currentValue.value]
}
if (!Array.isArray(currentLabel.value)) {
currentLabel.value = [currentLabel.value]
}
} else {
if (Array.isArray(currentValue.value)) {
currentValue.value = currentValue.value[0] ?? ''
}
if (Array.isArray(currentLabel.value)) {
currentLabel.value = currentLabel.value[0] ?? ''
}
}
function initValueAndLabel(value: string | number | (string | number)[]) {
if (!value) {
currentValues.value.length = 0
currentLabels.value.length = 0
return
}
)
function syncCurrentLabel() {
if (props.multiple && Array.isArray(currentValue.value)) {
if (!currentValue.value.length) {
currentLabel.value = []
return
}
const selectedValues = new Set(currentValue.value)
const options = optionStates.value
const selectedLabels: string[] = []
currentValues.value = !Array.isArray(value) ? [value] : value
for (let i = 0, len = options.length; i < len; ++i) {
const { value, label } = options[i]
const valueSet = new Set(currentValues.value)
const optionValueMap = optionMap.value
const selectedValues: (string | number)[] = []
const selectedLabels: string[] = []
if (selectedValues.has(value)) {
selectedValues.delete(value)
selectedLabels.push(label ?? value)
if (!selectedValues.size) break
}
}
currentLabel.value = selectedLabels
} else {
if (isNull(currentValue.value) || currentValue.value === '') {
currentLabel.value = ''
return
}
const option = optionStates.value.find(option => option.value === currentValue.value)
valueSet.forEach(value => {
const option = optionValueMap.get(value)
if (option) {
currentLabel.value = option.label ?? option.value
} else {
currentLabel.value = ''
selectedValues.push(value)
selectedLabels.push(option.label)
}
}
})
}
function isSelected(value: string | number) {
if (Array.isArray(currentValue.value)) {
return currentValue.value.includes(value)
if (props.multiple) {
return currentValues.value.includes(value)
}
return currentValue.value === value
return currentValues.value[0] === value
}
function computeListHeight() {
Expand Down Expand Up @@ -480,39 +425,38 @@ export default defineComponent({
}
function handleChange(value: string | number, label: string) {
if (
props.multiple &&
Array.isArray(currentValue.value) &&
Array.isArray(currentLabel.value)
) {
if (props.multiple) {
if (isSelected(value)) {
const index = currentValue.value.findIndex(v => v === value)
const index = currentValues.value.findIndex(v => v === value)
if (~index) {
currentValue.value.splice(index, 1)
currentLabel.value.splice(index, 1)
currentValues.value.splice(index, 1)
currentLabels.value.splice(index, 1)
}
} else {
currentValue.value.push(value)
currentLabel.value.push(label)
currentValues.value.push(value)
currentLabels.value.push(label)
}
emit('change', currentValue.value, currentLabel.value)
emit('update:value', currentValue.value)
const copiedValues = Array.from(currentValues.value)
emit('change', copiedValues, Array.from(currentLabels.value))
emit('update:value', copiedValues)
if (!props.disableValidate) {
validateField()
}
} else {
if (isNull(value) || value === '') {
currentLabel.value = ''
} else {
currentLabel.value = label
currentLabels.value.length = 0
if (!isNull(value) && value !== '') {
currentLabels.value.push(label)
}
const prevValue = currentValue.value
const prevValue = currentValues.value[0]
currentValue.value = value
currentValues.value.length = 0
currentValues.value.push(value)
if (prevValue !== value) {
emit('change', value, label)
Expand Down Expand Up @@ -548,11 +492,11 @@ export default defineComponent({
function handleClear() {
if (props.clearable) {
if (props.multiple) {
currentValue.value = []
currentLabel.value = []
currentValues.value = []
currentLabels.value = []
emit('change', currentValue.value, currentLabel.value)
emit('update:value', currentValue.value)
emit('change', currentValues.value, currentLabels.value)
emit('update:value', currentValues.value)
updatePopper()
} else {
Expand All @@ -569,8 +513,8 @@ export default defineComponent({
prefixCls: prefix,
locale,
currentVisible,
currentValue,
currentLabel,
currentValues,
currentLabels,
transferTo,
listHeight,
optionStates,
Expand All @@ -590,6 +534,7 @@ export default defineComponent({
popper,
virtualList,
isSelected,
computeListHeight,
handleSelect,
handleClick,
Expand Down
32 changes: 28 additions & 4 deletions docs/demos/cascader/size/demo.en-US.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
<template>
<Cascader
:value="value"
:options="options"
multiple
clearable
size="small"
placeholder="Small size"
></Cascader>
<br />
<br />
<Cascader
:options="options"
multiple
clearable
placeholder="Default size"
></Cascader>
<br />
<br />
<Cascader
:options="options"
multiple
clearable
size="large"
placeholder="Large size"
></Cascader>
<br />
<br />
<Cascader
:options="options"
multiple
clearable
style="--vxp-input-height: 48px;"
placeholder="Custom size"
></Cascader>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const value = ref(['Op-2', 'Op-2-5', 'Op-2-5-3'])
const options = createOptions(3)
function createOptions(depth: number, prefix = 'Op', iterator = 1) {
Expand Down
10 changes: 9 additions & 1 deletion docs/demos/cascader/size/demo.zh-CN.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@
multiple
clearable
size="small"
placeholder="有点太小了"
></Cascader>
<br />
<br />
<Cascader :options="options" multiple clearable></Cascader>
<Cascader
:options="options"
multiple
clearable
placeholder="比较正常"
></Cascader>
<br />
<br />
<Cascader
:options="options"
multiple
clearable
size="large"
placeholder="大一点的"
></Cascader>
<br />
<br />
Expand All @@ -23,6 +30,7 @@
multiple
clearable
style="--vxp-input-height: 48px;"
placeholder="大过头的"
></Cascader>
</template>

Expand Down
2 changes: 1 addition & 1 deletion docs/demos/select/height/desc.en-US.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### 长选项列表
### List Height

当选项数量过多时,会自动使用滚动条以方便用户浏览选项。

Expand Down
2 changes: 1 addition & 1 deletion docs/demos/select/height/desc.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### 长选项列表
### 列表高度

当选项数量过多时,会自动使用滚动条以方便用户浏览选项。

Expand Down
2 changes: 1 addition & 1 deletion docs/demos/select/label/desc.en-US.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
### 自定义显示
### Custom Label

有的场合,需要选项显示内容、选择器显示内容、选项值均不相同,可以结合选项的 `label` 属性和插槽实现。
2 changes: 1 addition & 1 deletion docs/demos/select/label/desc.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
### 自定义显示
### 自定义标签

有的场合,需要选项显示内容、选择器显示内容、选项值均不相同,可以结合选项的 `label` 属性和插槽实现。
2 changes: 1 addition & 1 deletion docs/demos/select/multiple/desc.en-US.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### 多选模式
### Multiple Select

添加 `multiple` 属性可以开启多选模式。

Expand Down
2 changes: 1 addition & 1 deletion docs/demos/select/options/desc.en-US.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
### 属性选项
### Options

`options` 属性可以直接传字符串,组件内部会自动处理。
Loading

0 comments on commit ae04af0

Please sign in to comment.