fix: select keyboard position error

refactor-list
tangjinzhou 2021-06-22 13:26:19 +08:00
parent 656d14fc4e
commit 604372ff2d
5 changed files with 40 additions and 17 deletions

View File

@ -0,0 +1,16 @@
import { Ref, ref, watch } from 'vue';
export default function useMemo<T>(
getValue: () => T,
condition: any[],
shouldUpdate: (prev: any[], next: any[]) => boolean,
) {
const cacheRef: Ref<T> = ref(getValue() as any);
watch(condition, (pre, next) => {
if (shouldUpdate(pre, next)) {
cacheRef.value = getValue();
}
});
return cacheRef;
}

View File

@ -14,6 +14,7 @@ import {
OnActiveValue, OnActiveValue,
} from './interface'; } from './interface';
import { RawValueType, FlattenOptionsType } from './interface/generator'; import { RawValueType, FlattenOptionsType } from './interface/generator';
import useMemo from '../_util/hooks/useMemo';
export interface OptionListProps { export interface OptionListProps {
prefixCls: string; prefixCls: string;
id: string; id: string;
@ -78,6 +79,12 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
setup(props) { setup(props) {
const itemPrefixCls = computed(() => `${props.prefixCls}-item`); const itemPrefixCls = computed(() => `${props.prefixCls}-item`);
const memoFlattenOptions = useMemo(
() => props.flattenOptions,
[() => props.open, () => props.flattenOptions],
(prev, next) => next[0] && prev[1] !== next[1],
);
// =========================== List =========================== // =========================== List ===========================
const listRef = createRef(); const listRef = createRef();
@ -93,12 +100,12 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
// ========================== Active ========================== // ========================== Active ==========================
const getEnabledActiveIndex = (index: number, offset = 1) => { const getEnabledActiveIndex = (index: number, offset = 1) => {
const len = props.flattenOptions.length; const len = memoFlattenOptions.value.length;
for (let i = 0; i < len; i += 1) { for (let i = 0; i < len; i += 1) {
const current = (index + i * offset + len) % len; 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) { if (!group && !(data as OptionData).disabled) {
return current; return current;
} }
@ -115,7 +122,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
const info = { source: fromKeyboard ? ('keyboard' as const) : ('mouse' as const) }; const info = { source: fromKeyboard ? ('keyboard' as const) : ('mouse' as const) };
// Trigger active event // Trigger active event
const flattenItem = props.flattenOptions[index]; const flattenItem = memoFlattenOptions.value[index];
if (!flattenItem) { if (!flattenItem) {
props.onActiveValue(null, -1, info); props.onActiveValue(null, -1, info);
return; return;
@ -127,7 +134,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
// Auto active first item when list length or searchValue changed // Auto active first item when list length or searchValue changed
watch( watch(
computed(() => [props.flattenOptions.length, props.searchValue]), [() => memoFlattenOptions.value.length, () => props.searchValue],
() => { () => {
setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1); setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
}, },
@ -136,11 +143,11 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
// Auto scroll to item position in single mode // Auto scroll to item position in single mode
watch( watch(
computed(() => props.open), () => props.open,
() => { () => {
if (!props.multiple && props.open && props.values.size === 1) { if (!props.multiple && props.open && props.values.size === 1) {
const value = Array.from(props.values)[0]; 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); setActive(index);
scrollIntoView(index); scrollIntoView(index);
} }
@ -167,7 +174,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
}; };
function renderItem(index: number) { function renderItem(index: number) {
const item = props.flattenOptions[index]; const item = memoFlattenOptions.value[index];
if (!item) return null; if (!item) return null;
const itemData = (item.data || {}) as OptionData; const itemData = (item.data || {}) as OptionData;
@ -188,6 +195,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
) : null; ) : null;
} }
return { return {
memoFlattenOptions,
renderItem, renderItem,
listRef, listRef,
state, state,
@ -220,7 +228,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
// >>> Select // >>> Select
case KeyCode.ENTER: { case KeyCode.ENTER: {
// value // value
const item = props.flattenOptions[state.activeIndex]; const item = memoFlattenOptions.value[state.activeIndex];
if (item && !item.data.disabled) { if (item && !item.data.disabled) {
onSelectValue(item.data.value); onSelectValue(item.data.value);
} else { } else {
@ -258,6 +266,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
itemPrefixCls, itemPrefixCls,
setActive, setActive,
onSelectValue, onSelectValue,
memoFlattenOptions,
} = this as any; } = this as any;
const { const {
id, id,
@ -265,7 +274,6 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
values, values,
height, height,
itemHeight, itemHeight,
flattenOptions,
menuItemSelectedIcon, menuItemSelectedIcon,
notFoundContent, notFoundContent,
virtual, virtual,
@ -274,7 +282,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
} = this.$props as OptionListProps; } = this.$props as OptionListProps;
const { activeIndex } = this.state; const { activeIndex } = this.state;
// ========================== Render ========================== // ========================== Render ==========================
if (flattenOptions.length === 0) { if (memoFlattenOptions.length === 0) {
return ( return (
<div <div
role="listbox" role="listbox"
@ -296,7 +304,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
<List <List
itemKey="key" itemKey="key"
ref={listRef} ref={listRef}
data={flattenOptions} data={memoFlattenOptions}
height={height} height={height}
itemHeight={itemHeight} itemHeight={itemHeight}
fullHeight={false} fullHeight={false}

View File

@ -11,7 +11,7 @@ import {
import PropTypes from '../../_util/vue-types'; import PropTypes from '../../_util/vue-types';
import { RefObject } from '../../_util/createRef'; import { RefObject } from '../../_util/createRef';
import antInput from '../../_util/antInputDirective'; import antInput from '../../_util/antInputDirective';
import classNames from 'ant-design-vue/es/_util/classNames'; import classNames from '../../_util/classNames';
interface InputProps { interface InputProps {
prefixCls: string; prefixCls: string;

View File

@ -50,7 +50,7 @@ const SingleSelector = defineComponent<SelectorProps>({
return inputValue; return inputValue;
}); });
watch( watch(
computed(() => [combobox.value, props.activeValue]), [combobox, () => props.activeValue],
() => { () => {
if (combobox.value) { if (combobox.value) {
inputChanged.value = false; inputChanged.value = false;

View File

@ -397,9 +397,9 @@ export default function generateSelector<
// ============================== Ref =============================== // ============================== Ref ===============================
const selectorDomRef = createRef(); const selectorDomRef = createRef();
const mergedValue = ref(undefined); const mergedValue = ref();
watch( watch(
computed(() => [props.value, props.defaultValue]), () => props.value,
() => { () => {
mergedValue.value = props.value !== undefined ? props.value : props.defaultValue; mergedValue.value = props.value !== undefined ? props.value : props.defaultValue;
}, },
@ -801,7 +801,7 @@ export default function generateSelector<
// Close dropdown when disabled change // Close dropdown when disabled change
watch( watch(
computed(() => props.disabled), () => props.disabled,
() => { () => {
if (innerOpen.value && !!props.disabled) { if (innerOpen.value && !!props.disabled) {
setInnerOpen(false); setInnerOpen(false);
@ -1355,7 +1355,6 @@ export default function generateSelector<
); );
}, },
}); });
Select.inheritAttrs = false;
Select.props = initDefaultProps(BaseProps(), {}); Select.props = initDefaultProps(BaseProps(), {});
return Select; return Select;
} }