From 604372ff2da521dd580ad5229f7dbd445c1c6190 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Tue, 22 Jun 2021 13:26:19 +0800 Subject: [PATCH] fix: select keyboard position error --- components/_util/hooks/useMemo.ts | 16 ++++++++++ components/vc-select/OptionList.tsx | 30 ++++++++++++------- components/vc-select/Selector/Input.tsx | 2 +- .../vc-select/Selector/SingleSelector.tsx | 2 +- components/vc-select/generate.tsx | 7 ++--- 5 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 components/_util/hooks/useMemo.ts diff --git a/components/_util/hooks/useMemo.ts b/components/_util/hooks/useMemo.ts new file mode 100644 index 0000000000..3aab04b5bb --- /dev/null +++ b/components/_util/hooks/useMemo.ts @@ -0,0 +1,16 @@ +import { Ref, ref, watch } from 'vue'; + +export default function useMemo( + getValue: () => T, + condition: any[], + shouldUpdate: (prev: any[], next: any[]) => boolean, +) { + const cacheRef: Ref = ref(getValue() as any); + watch(condition, (pre, next) => { + if (shouldUpdate(pre, next)) { + cacheRef.value = getValue(); + } + }); + + return cacheRef; +} diff --git a/components/vc-select/OptionList.tsx b/components/vc-select/OptionList.tsx index f5335fea38..abea931ed1 100644 --- a/components/vc-select/OptionList.tsx +++ b/components/vc-select/OptionList.tsx @@ -14,6 +14,7 @@ import { OnActiveValue, } from './interface'; import { RawValueType, FlattenOptionsType } from './interface/generator'; +import useMemo from '../_util/hooks/useMemo'; export interface OptionListProps { prefixCls: string; id: string; @@ -78,6 +79,12 @@ const OptionList = defineComponent({ setup(props) { const itemPrefixCls = computed(() => `${props.prefixCls}-item`); + const memoFlattenOptions = useMemo( + () => props.flattenOptions, + [() => props.open, () => props.flattenOptions], + (prev, next) => next[0] && prev[1] !== next[1], + ); + // =========================== List =========================== const listRef = createRef(); @@ -93,12 +100,12 @@ const OptionList = defineComponent({ // ========================== Active ========================== const getEnabledActiveIndex = (index: number, offset = 1) => { - const len = props.flattenOptions.length; + const len = memoFlattenOptions.value.length; for (let i = 0; i < len; i += 1) { const current = (index + i * offset + len) % len; - const { group, data } = props.flattenOptions[current]; + const { group, data } = memoFlattenOptions.value[current]; if (!group && !(data as OptionData).disabled) { return current; } @@ -115,7 +122,7 @@ const OptionList = defineComponent({ const info = { source: fromKeyboard ? ('keyboard' as const) : ('mouse' as const) }; // Trigger active event - const flattenItem = props.flattenOptions[index]; + const flattenItem = memoFlattenOptions.value[index]; if (!flattenItem) { props.onActiveValue(null, -1, info); return; @@ -127,7 +134,7 @@ const OptionList = defineComponent({ // Auto active first item when list length or searchValue changed watch( - computed(() => [props.flattenOptions.length, props.searchValue]), + [() => memoFlattenOptions.value.length, () => props.searchValue], () => { setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1); }, @@ -136,11 +143,11 @@ const OptionList = defineComponent({ // Auto scroll to item position in single mode watch( - computed(() => props.open), + () => props.open, () => { if (!props.multiple && props.open && props.values.size === 1) { const value = Array.from(props.values)[0]; - const index = props.flattenOptions.findIndex(({ data }) => data.value === value); + const index = memoFlattenOptions.value.findIndex(({ data }) => data.value === value); setActive(index); scrollIntoView(index); } @@ -167,7 +174,7 @@ const OptionList = defineComponent({ }; function renderItem(index: number) { - const item = props.flattenOptions[index]; + const item = memoFlattenOptions.value[index]; if (!item) return null; const itemData = (item.data || {}) as OptionData; @@ -188,6 +195,7 @@ const OptionList = defineComponent({ ) : null; } return { + memoFlattenOptions, renderItem, listRef, state, @@ -220,7 +228,7 @@ const OptionList = defineComponent({ // >>> Select case KeyCode.ENTER: { // value - const item = props.flattenOptions[state.activeIndex]; + const item = memoFlattenOptions.value[state.activeIndex]; if (item && !item.data.disabled) { onSelectValue(item.data.value); } else { @@ -258,6 +266,7 @@ const OptionList = defineComponent({ itemPrefixCls, setActive, onSelectValue, + memoFlattenOptions, } = this as any; const { id, @@ -265,7 +274,6 @@ const OptionList = defineComponent({ values, height, itemHeight, - flattenOptions, menuItemSelectedIcon, notFoundContent, virtual, @@ -274,7 +282,7 @@ const OptionList = defineComponent({ } = this.$props as OptionListProps; const { activeIndex } = this.state; // ========================== Render ========================== - if (flattenOptions.length === 0) { + if (memoFlattenOptions.length === 0) { return (
({ ({ return inputValue; }); watch( - computed(() => [combobox.value, props.activeValue]), + [combobox, () => props.activeValue], () => { if (combobox.value) { inputChanged.value = false; diff --git a/components/vc-select/generate.tsx b/components/vc-select/generate.tsx index b0c39b273e..ac1ad11a2d 100644 --- a/components/vc-select/generate.tsx +++ b/components/vc-select/generate.tsx @@ -397,9 +397,9 @@ export default function generateSelector< // ============================== Ref =============================== const selectorDomRef = createRef(); - const mergedValue = ref(undefined); + const mergedValue = ref(); watch( - computed(() => [props.value, props.defaultValue]), + () => props.value, () => { mergedValue.value = props.value !== undefined ? props.value : props.defaultValue; }, @@ -801,7 +801,7 @@ export default function generateSelector< // Close dropdown when disabled change watch( - computed(() => props.disabled), + () => props.disabled, () => { if (innerOpen.value && !!props.disabled) { setInnerOpen(false); @@ -1355,7 +1355,6 @@ export default function generateSelector< ); }, }); - Select.inheritAttrs = false; Select.props = initDefaultProps(BaseProps(), {}); return Select; }