From 249a3c141d4819aca5ff147ff8cadaee301e0f9a Mon Sep 17 00:00:00 2001 From: chenxi24 Date: Tue, 7 Dec 2021 23:04:56 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat=20:=E7=BB=99=E5=8F=AF=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E4=B8=8B=E6=8B=89=E8=BE=93=E5=85=A5=E6=A1=86=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=94=AE=E7=9B=98=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/dropdown.tsx | 4 +- .../src/composable/use-keyBoard-select.ts | 73 +++++++++++++++++++ .../editable-select/src/editable-select.tsx | 25 ++++++- .../docs/components/editable-select/index.md | 2 +- 4 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts diff --git a/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx b/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx index 711f94ee..7f1f029b 100644 --- a/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx +++ b/packages/devui-vue/devui/editable-select/src/components/dropdown.tsx @@ -14,6 +14,7 @@ export default defineComponent({ renderDefaultSlots, renderEmptySlots, selectedIndex, + hoverIndex, loadMore } = select const { maxHeight } = selectProps @@ -22,7 +23,8 @@ export default defineComponent({ const { disabledKey } = selectProps return className('devui-dropdown-item', { disabled: disabledKey ? !!item[disabledKey] : false, - selected: selectedIndex.value === index + selected: selectedIndex.value === index, + 'devui-dropdown-bg': hoverIndex.value === index }) } return ( diff --git a/packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts b/packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts new file mode 100644 index 00000000..6f679776 --- /dev/null +++ b/packages/devui-vue/devui/editable-select/src/composable/use-keyBoard-select.ts @@ -0,0 +1,73 @@ +import { ComputedRef, nextTick, Ref } from 'vue' +import { OptionItem } from '../editable-select-types' +interface keyBoardSelectReturnType { + handleKeydown: (e: KeyboardEvent) => void +} + +export default function keyBoardSelect( + dropdownRef: Ref, + visible: Ref, + hoverIndex: Ref, + selectedIndex: Ref, + filteredOptions: ComputedRef, + toggleMenu: () => void, + selectOptionClick: (e: KeyboardEvent, item: OptionItem) => void +): keyBoardSelectReturnType { + const updateHoverIndex = (index: number) => { + hoverIndex.value = index + } + const scrollToActive = (index: number) => { + const dropdownVal = dropdownRef.value + const li = dropdownVal.children[index] + + nextTick(() => { + if (li.scrollIntoViewIfNeeded) { + li.scrollIntoViewIfNeeded(false) + } else { + const containerInfo = dropdownVal.getBoundingClientRect() + const elementInfo = li.getBoundingClientRect() + if (elementInfo.bottom > containerInfo.bottom || elementInfo.top < containerInfo.top) { + li.scrollIntoView(false) + } + } + }) + } + const onKeyboardSelect = (e: KeyboardEvent) => { + const option = filteredOptions.value[hoverIndex.value] + selectOptionClick(e, option) + hoverIndex.value = selectedIndex.value + } + const handleKeydown = (e: KeyboardEvent) => { + const keyCode = e.key || e.code + let index = 0 + if (!visible.value) { + toggleMenu() + } + + if (keyCode === 'Backspace') { + return + } + + if (keyCode === 'ArrowUp') { + index = hoverIndex.value - 1 + if (index < 0) { + index = filteredOptions.value.length - 1 + } + } else if (keyCode === 'ArrowDown') { + index = hoverIndex.value + 1 + if (index > filteredOptions.value.length - 1) { + index = 0 + } + } + + if (keyCode === 'Enter') { + return onKeyboardSelect(e) + } + updateHoverIndex(index) + scrollToActive(index) + } + + return { + handleKeydown + } +} diff --git a/packages/devui-vue/devui/editable-select/src/editable-select.tsx b/packages/devui-vue/devui/editable-select/src/editable-select.tsx index 851816c2..ef554012 100644 --- a/packages/devui-vue/devui/editable-select/src/editable-select.tsx +++ b/packages/devui-vue/devui/editable-select/src/editable-select.tsx @@ -19,6 +19,7 @@ import './editable-select.scss' import ClickOutside from '../../shared/devui-directive/clickoutside' import { debounce } from 'lodash' import { className } from './utils' +import keyBoardSelect from './composable/use-keyBoard-select' export default defineComponent({ name: 'DEditableSelect', directives: { ClickOutside }, @@ -66,6 +67,7 @@ export default defineComponent({ const visible = ref(false) const inputValue = ref('') const selectedIndex = ref(0) + const hoverIndex = ref(0) const query = ref(props.modelValue) const position = reactive({ originX: 'left', @@ -155,7 +157,7 @@ export default defineComponent({ } } - const selectOptionClick = (e, item) => { + const selectOptionClick = (e, item: OptionItem) => { const { disabledKey } = props if (disabledKey && item[disabledKey]) { e.stopPropagation() @@ -164,6 +166,7 @@ export default defineComponent({ selectedIndex.value = findIndex(item) inputValue.value = '' ctx.emit('update:modelValue', item.name) + visible.value = false } } @@ -174,6 +177,16 @@ export default defineComponent({ props.loadMore() } } + const { handleKeydown } = keyBoardSelect( + dropdownRef, + visible, + hoverIndex, + selectedIndex, + filteredOptions, + toggleMenu, + selectOptionClick + ) + provide('InjectionKey', { dropdownRef, props: reactive({ @@ -182,6 +195,7 @@ export default defineComponent({ visible, emptyText, selectedIndex, + hoverIndex, loadMore, selectOptionClick, renderDefaultSlots, @@ -201,7 +215,14 @@ export default defineComponent({ return ( <>
- +