mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
chore: wip
This commit is contained in:
@@ -36,12 +36,13 @@ export default defineComponent({
|
||||
const minWidth = ref('')
|
||||
|
||||
function updateMinWidth() {
|
||||
minWidth.value = `${select!.selectRef?.offsetWidth}px` }
|
||||
minWidth.value = `${select!.selectRef?.offsetWidth}px`
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// TODO: updatePopper
|
||||
// popper.value.update()
|
||||
if(select) {
|
||||
if (select) {
|
||||
updateMinWidth()
|
||||
useResizeObserver(select.selectRef, updateMinWidth)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
reactive,
|
||||
ref,
|
||||
watch,
|
||||
watchEffect,
|
||||
} from 'vue'
|
||||
import { get, isEqual } from 'lodash-unified'
|
||||
import {
|
||||
@@ -37,19 +36,21 @@ export const useFlatSelect = (props: SelectProps, emit: FlatSelectEmits) => {
|
||||
const nsSelect = useNamespace('select')
|
||||
|
||||
const states = reactive<SelectStates>({
|
||||
inputValue: '',
|
||||
options: new Map(),
|
||||
cachedOptions: new Map(),
|
||||
optionValues: [], // sorted value of options
|
||||
selected: [],
|
||||
selectionWidth: 0,
|
||||
collapseItemWidth: 0,
|
||||
selectedLabel: '',
|
||||
hoveringIndex: -1,
|
||||
|
||||
//TODO: maybe move this to useSelect
|
||||
selectionWidth: 0,
|
||||
selectedLabel: '',
|
||||
inputValue: '',
|
||||
isBeforeHide: false,
|
||||
previousQuery: null,
|
||||
inputHovering: false,
|
||||
menuVisibleOnFocus: false,
|
||||
isBeforeHide: false,
|
||||
})
|
||||
|
||||
// template refs
|
||||
@@ -129,24 +130,6 @@ export const useFlatSelect = (props: SelectProps, emit: FlatSelectEmits) => {
|
||||
})
|
||||
}
|
||||
|
||||
//TODO: maybe remove
|
||||
//watch(
|
||||
// () => props.modelValue,
|
||||
// (val, oldVal) => {
|
||||
// if (props.multiple) {
|
||||
// if (props.filterable && !props.reserveKeyword) {
|
||||
// states.inputValue = ''
|
||||
// handleQueryChange('')
|
||||
// }
|
||||
// }
|
||||
// setSelected()
|
||||
// },
|
||||
// {
|
||||
// flush: 'post',
|
||||
// deep: true,
|
||||
// }
|
||||
//)
|
||||
|
||||
watch(
|
||||
// fix `Array.prototype.push/splice/..` cannot trigger non-deep watcher
|
||||
// https://github.com/vuejs/vue-next/issues/2116
|
||||
@@ -167,17 +150,7 @@ export const useFlatSelect = (props: SelectProps, emit: FlatSelectEmits) => {
|
||||
}
|
||||
)
|
||||
|
||||
watchEffect(() => {
|
||||
// Anything could cause options changed, then update options
|
||||
// If you want to control it by condition, write here
|
||||
if (states.isBeforeHide) return
|
||||
updateOptions()
|
||||
})
|
||||
|
||||
const handleQueryChange = (val: string) => {
|
||||
//if (states.previousQuery === val || isComposing.value) {
|
||||
// return
|
||||
//}
|
||||
states.previousQuery = val
|
||||
if (props.filterable && isFunction(props.filterMethod)) {
|
||||
props.filterMethod(val)
|
||||
@@ -309,13 +282,7 @@ export const useFlatSelect = (props: SelectProps, emit: FlatSelectEmits) => {
|
||||
} else {
|
||||
emit(UPDATE_MODEL_EVENT, option.value)
|
||||
emitChange(option.value)
|
||||
//TODO: handle in useSelect
|
||||
//expanded.value = false
|
||||
}
|
||||
//if (expanded.value) return
|
||||
nextTick(() => {
|
||||
scrollToOption(option)
|
||||
})
|
||||
}
|
||||
|
||||
const getValueIndex = (arr: OptionValue[], option: OptionPublicInstance) => {
|
||||
@@ -397,6 +364,7 @@ export const useFlatSelect = (props: SelectProps, emit: FlatSelectEmits) => {
|
||||
optionsArray,
|
||||
filteredOptionsCount,
|
||||
handleOptionSelect,
|
||||
handleQueryChange, // internal
|
||||
scrollToOption,
|
||||
hasModelValue,
|
||||
updateOptions,
|
||||
@@ -427,7 +395,6 @@ export const useFlatSelect = (props: SelectProps, emit: FlatSelectEmits) => {
|
||||
})
|
||||
)
|
||||
|
||||
//TODO:
|
||||
provide('flat-select', FLAT_SELECT_API)
|
||||
|
||||
return FLAT_SELECT_API
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
debugWarn,
|
||||
ensureArray,
|
||||
isArray,
|
||||
isClient,
|
||||
isFunction,
|
||||
isIOS,
|
||||
isObject,
|
||||
@@ -58,8 +57,17 @@ import type {
|
||||
|
||||
export const useSelect = (props: SelectProps, emit: SelectEmits) => {
|
||||
const FLAT_SELECT_API = useFlatSelect(props, emit)
|
||||
const { t, contentId, nsSelect, setSelected, states, menuRef, scrollbarRef } =
|
||||
FLAT_SELECT_API
|
||||
const {
|
||||
t,
|
||||
contentId,
|
||||
nsSelect,
|
||||
setSelected,
|
||||
states,
|
||||
menuRef,
|
||||
scrollbarRef,
|
||||
handleOptionSelect: _handleOptionSelect,
|
||||
handleQueryChange: _handleQueryChange,
|
||||
} = FLAT_SELECT_API
|
||||
const nsInput = useNamespace('input')
|
||||
|
||||
// template refs
|
||||
@@ -243,7 +251,6 @@ export const useSelect = (props: SelectProps, emit: SelectEmits) => {
|
||||
}
|
||||
}
|
||||
setSelected()
|
||||
//TODO: maybe remove
|
||||
if (!isEqual(val, oldVal) && props.validateEvent) {
|
||||
formItem?.validate('change').catch((err) => debugWarn(err))
|
||||
}
|
||||
@@ -268,26 +275,26 @@ export const useSelect = (props: SelectProps, emit: SelectEmits) => {
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
// fix `Array.prototype.push/splice/..` cannot trigger non-deep watcher
|
||||
// https://github.com/vuejs/vue-next/issues/2116
|
||||
() => states.options.entries(),
|
||||
() => {
|
||||
if (!isClient) return
|
||||
// tooltipRef.value?.updatePopper?.()
|
||||
setSelected()
|
||||
if (
|
||||
props.defaultFirstOption &&
|
||||
(props.filterable || props.remote) &&
|
||||
filteredOptionsCount.value
|
||||
) {
|
||||
checkDefaultFirstOption()
|
||||
}
|
||||
},
|
||||
{
|
||||
flush: 'post',
|
||||
}
|
||||
)
|
||||
//watch(
|
||||
// // fix `Array.prototype.push/splice/..` cannot trigger non-deep watcher
|
||||
// // https://github.com/vuejs/vue-next/issues/2116
|
||||
// () => states.options.entries(),
|
||||
// () => {
|
||||
// if (!isClient) return
|
||||
// // tooltipRef.value?.updatePopper?.()
|
||||
// setSelected()
|
||||
// if (
|
||||
// props.defaultFirstOption &&
|
||||
// (props.filterable || props.remote) &&
|
||||
// filteredOptionsCount.value
|
||||
// ) {
|
||||
// checkDefaultFirstOption()
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// flush: 'post',
|
||||
// }
|
||||
//)
|
||||
|
||||
//TODO: maybe delete
|
||||
watch([() => states.hoveringIndex, optionsArray], ([val]) => {
|
||||
@@ -308,62 +315,6 @@ export const useSelect = (props: SelectProps, emit: SelectEmits) => {
|
||||
updateOptions()
|
||||
})
|
||||
|
||||
const handleQueryChange = (val: string) => {
|
||||
if (states.previousQuery === val || isComposing.value) {
|
||||
return
|
||||
}
|
||||
states.previousQuery = val
|
||||
if (props.filterable && isFunction(props.filterMethod)) {
|
||||
props.filterMethod(val)
|
||||
} else if (
|
||||
props.filterable &&
|
||||
props.remote &&
|
||||
isFunction(props.remoteMethod)
|
||||
) {
|
||||
props.remoteMethod(val)
|
||||
}
|
||||
if (
|
||||
props.defaultFirstOption &&
|
||||
(props.filterable || props.remote) &&
|
||||
filteredOptionsCount.value
|
||||
) {
|
||||
nextTick(checkDefaultFirstOption)
|
||||
} else {
|
||||
nextTick(updateHoveringIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find and highlight first option as default selected
|
||||
* @remark
|
||||
* - if the first option in dropdown list is user-created,
|
||||
* it would be at the end of the optionsArray
|
||||
* so find it and set hover.
|
||||
* (NOTE: there must be only one user-created option in dropdown list with query)
|
||||
* - if there's no user-created option in list, just find the first one as usual
|
||||
* (NOTE: exclude options that are disabled or in disabled-group)
|
||||
*/
|
||||
const checkDefaultFirstOption = () => {
|
||||
const optionsInDropdown = optionsArray.value.filter(
|
||||
(n) => n.visible && !n.disabled && !n.states.groupDisabled
|
||||
)
|
||||
const userCreatedOption = optionsInDropdown.find((n) => n.created)
|
||||
const firstOriginOption = optionsInDropdown[0]
|
||||
const valueList = optionsArray.value.map((item) => item.value)
|
||||
states.hoveringIndex = getValueIndex(
|
||||
valueList,
|
||||
userCreatedOption || firstOriginOption
|
||||
)
|
||||
}
|
||||
|
||||
const updateHoveringIndex = () => {
|
||||
states.hoveringIndex = optionsArray.value.findIndex((item) =>
|
||||
states.selected.some(
|
||||
(selected) => getValueKey(selected) === getValueKey(item)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const resetSelectionWidth = () => {
|
||||
states.selectionWidth = Number.parseFloat(
|
||||
window.getComputedStyle(selectionRef.value!).width
|
||||
@@ -462,46 +413,37 @@ export const useSelect = (props: SelectProps, emit: SelectEmits) => {
|
||||
focus()
|
||||
}
|
||||
|
||||
const handleOptionSelect = (option: OptionPublicInstance) => {
|
||||
if (props.multiple) {
|
||||
const value = ensureArray(props.modelValue ?? []).slice()
|
||||
const optionIndex = getValueIndex(value, option)
|
||||
if (optionIndex > -1) {
|
||||
value.splice(optionIndex, 1)
|
||||
} else if (
|
||||
props.multipleLimit <= 0 ||
|
||||
value.length < props.multipleLimit
|
||||
) {
|
||||
value.push(option.value)
|
||||
}
|
||||
emit(UPDATE_MODEL_EVENT, value)
|
||||
emitChange(value)
|
||||
if (option.created) {
|
||||
handleQueryChange('')
|
||||
}
|
||||
if (props.filterable && !props.reserveKeyword) {
|
||||
states.inputValue = ''
|
||||
}
|
||||
} else {
|
||||
emit(UPDATE_MODEL_EVENT, option.value)
|
||||
emitChange(option.value)
|
||||
expanded.value = false
|
||||
}
|
||||
focus()
|
||||
if (expanded.value) return
|
||||
nextTick(() => {
|
||||
scrollToOption(option)
|
||||
})
|
||||
}
|
||||
|
||||
const getValueIndex = (arr: OptionValue[], option: OptionPublicInstance) => {
|
||||
if (isUndefined(option)) return -1
|
||||
if (!isObject(option.value)) return arr.indexOf(option.value)
|
||||
|
||||
return arr.findIndex((item) => {
|
||||
return isEqual(get(item, props.valueKey), getValueKey(option))
|
||||
})
|
||||
}
|
||||
//const handleOptionSelect = (option: OptionPublicInstance) => {
|
||||
// if (props.multiple) {
|
||||
// const value = ensureArray(props.modelValue ?? []).slice()
|
||||
// const optionIndex = getValueIndex(value, option)
|
||||
// if (optionIndex > -1) {
|
||||
// value.splice(optionIndex, 1)
|
||||
// } else if (
|
||||
// props.multipleLimit <= 0 ||
|
||||
// value.length < props.multipleLimit
|
||||
// ) {
|
||||
// value.push(option.value)
|
||||
// }
|
||||
// emit(UPDATE_MODEL_EVENT, value)
|
||||
// emitChange(value)
|
||||
// if (option.created) {
|
||||
// handleQueryChange('')
|
||||
// }
|
||||
// if (props.filterable && !props.reserveKeyword) {
|
||||
// states.inputValue = ''
|
||||
// }
|
||||
// } else {
|
||||
// emit(UPDATE_MODEL_EVENT, option.value)
|
||||
// emitChange(option.value)
|
||||
// expanded.value = false
|
||||
// }
|
||||
// focus()
|
||||
// if (expanded.value) return
|
||||
// nextTick(() => {
|
||||
// scrollToOption(option)
|
||||
// })
|
||||
//}
|
||||
|
||||
const scrollToOption = (
|
||||
option:
|
||||
@@ -685,6 +627,23 @@ export const useSelect = (props: SelectProps, emit: SelectEmits) => {
|
||||
const collapseTagStyle = computed(() => {
|
||||
return { maxWidth: `${states.selectionWidth}px` }
|
||||
})
|
||||
function handleQueryChange(val: string) {
|
||||
if (states.previousQuery === val || isComposing.value) {
|
||||
return
|
||||
}
|
||||
_handleQueryChange(val)
|
||||
}
|
||||
|
||||
function handleOptionSelect(option: OptionPublicInstance) {
|
||||
_handleOptionSelect(option)
|
||||
if (!props.multiple) {
|
||||
expanded.value = false
|
||||
}
|
||||
if (expanded.value) return
|
||||
nextTick(() => {
|
||||
scrollToOption(option)
|
||||
})
|
||||
}
|
||||
|
||||
useResizeObserver(selectionRef, resetSelectionWidth)
|
||||
useResizeObserver(menuRef, updateTooltip)
|
||||
|
||||
Reference in New Issue
Block a user