Skip to content

Commit

Permalink
feat(select): 列表展开时定位置选中项 (#1068)
Browse files Browse the repository at this point in the history
* feat(select): 列表展开时定位置选中项

列表展开时定位置选中项

closed #111

* fix(select): 事例优化

* feat(select): 修改 expose 数据命名

* feat(select): 使用provide inject传递参数

Co-authored-by: 18651688439 <1164668598@qq.com>
  • Loading branch information
huoyuhao and 18651688439 committed Jun 27, 2022
1 parent 2486928 commit a78aa9d
Show file tree
Hide file tree
Showing 8 changed files with 439 additions and 170 deletions.
14 changes: 2 additions & 12 deletions examples/select/demos/base.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<template>
<div class="tdesign-demo-select-base">
<t-space>
<!-- 方式一:使用 options 输出下拉选项。优先级高于 t-option-->
<t-select v-model="value1" :options="options1" placeholder="请选择云解决方案" />

<!-- 方式二:使用 t-option 输出下拉选项。options 和 t-option 两种实现方式二选一即可 -->
<t-select v-model="value2" placeholder="请选择云产品">
<t-option v-for="item in options2" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</div>
</t-space>
</template>
<script setup lang="jsx">
import { ref } from 'vue';
Expand Down Expand Up @@ -37,13 +37,3 @@ const options2 = [
const value1 = ref('');
const value2 = ref('');
</script>
<style scoped>
.tdesign-demo-select-base {
width: 450px;
display: flex;
}
.tdesign-demo-select-base .t-select__wrap + .t-select__wrap {
margin-left: 36px;
}
</style>
4 changes: 2 additions & 2 deletions examples/select/demos/creatable.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="tdesign-demo-block-row">
<t-space>
<t-select
v-model="value1"
creatable
Expand All @@ -17,7 +17,7 @@
:options="options"
@create="createOptions"
/>
</div>
</t-space>
</template>
<script setup>
import { ref } from 'vue';
Expand Down
18 changes: 18 additions & 0 deletions examples/select/demos/scroll-top.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<t-space>
<t-select v-model="value1" :options="options1" placeholder="请选择" />
<t-select v-model="value2" :options="options1" placeholder="请选择" multiple />
</t-space>
</template>
<script setup lang="jsx">
import { ref } from 'vue';
const options = [];
for (let i = 0; i < 100; i++) {
options.push({ label: `${i}`, value: i });
}
const options1 = options;
const value1 = ref(50);
const value2 = ref([50, 70]);
</script>
9 changes: 9 additions & 0 deletions src/popup/popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,15 @@ export default defineComponent({
updatePopper();
},
);
const updateScrollTop: Function = inject('updateScrollTop', () => {});
watch(
() => [innerVisible.value, overlayEl.value],
() => {
if (innerVisible.value && overlayEl.value && updateScrollTop) {
updateScrollTop?.(overlayEl.value);
}
},
);

watch(
() => props.placement,
Expand Down
10 changes: 8 additions & 2 deletions src/select/select-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, defineComponent, inject, PropType, Slots } from 'vue';
import { computed, defineComponent, inject, PropType, Slots, ref } from 'vue';
import isFunction from 'lodash/isFunction';

import { SelectOption, SelectOptionGroup, TdOptionProps } from './type';
Expand Down Expand Up @@ -28,12 +28,13 @@ export default defineComponent({
default: (): SelectOption[] => [],
},
},
setup(props) {
setup(props, { expose }) {
const COMPONENT_NAME = usePrefixClass('select');
const renderTNodeJSX = useTNodeJSX();
const renderDefaultTNode = useTNodeDefault();
const { t, global } = useConfig('select');
const tSelect = inject(selectInjectKey);
const innerRef = ref<HTMLElement>(null);

const showCreateOption = computed(() => props.creatable && props.filterable && props.inputValue);

Expand Down Expand Up @@ -103,8 +104,13 @@ export default defineComponent({
}[tSelect.value.size];
});

expose({
innerRef,
});

return () => (
<div
ref={innerRef}
class={[
`${COMPONENT_NAME.value}__dropdown-inner`,
`${COMPONENT_NAME.value}__dropdown-inner--size-${dropdownInnerSize.value}`,
Expand Down
31 changes: 30 additions & 1 deletion src/select/select.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineComponent, provide, computed, toRefs, watch, ref } from 'vue';
import { defineComponent, provide, computed, toRefs, watch, ref, nextTick } from 'vue';
import picker from 'lodash/pick';
import isArray from 'lodash/isArray';
import isFunction from 'lodash/isFunction';
Expand Down Expand Up @@ -27,12 +27,14 @@ export default defineComponent({
name: 'TSelect',
props: { ...props },
setup(props: TdSelectProps, { slots }) {
const classPrefix = usePrefixClass();
const disabled = useFormDisabled();
const renderTNodeJSX = useTNodeJSX();
const COMPONENT_NAME = usePrefixClass('select');
const { global, t } = useConfig('select');
const { popupVisible, inputValue, modelValue, value } = toRefs(props);
const [orgValue, seOrgValue] = useVModel(value, modelValue, props.defaultValue, props.onChange);
const selectPanelRef = ref(null);

const keys = computed(() => ({
label: props.keys?.label || 'label',
Expand Down Expand Up @@ -235,6 +237,32 @@ export default defineComponent({
}
});

// 列表展开时定位置选中项
const updateScrollTop = (content: HTMLDivElement) => {
if (!selectPanelRef.value) {
return;
}
const firstSelectedNode: HTMLDivElement = (selectPanelRef.value?.innerRef as HTMLDivElement)?.querySelector(
`.${classPrefix.value}-is-selected`,
);
// 此处需要等待渲染后进行计算
nextTick(() => {
if (firstSelectedNode && content) {
const { paddingBottom } = getComputedStyle(firstSelectedNode);
const { marginBottom } = getComputedStyle(content);
const elementBottomHeight = parseInt(paddingBottom, 10) + parseInt(marginBottom, 10);
// 小于0时不需要特殊处理,会被设为0
const updateValue =
firstSelectedNode.offsetTop -
content.offsetTop -
(content.clientHeight - firstSelectedNode.clientHeight) +
elementBottomHeight;
// eslint-disable-next-line no-param-reassign
content.scrollTop = updateValue;
}
});
};
provide('updateScrollTop', updateScrollTop);
return () => {
const { overlayClassName, ...restPopupProps } = (props.popupProps || {}) as TdSelectProps['popupProps'];
return (
Expand Down Expand Up @@ -313,6 +341,7 @@ export default defineComponent({
v-slots={{
panel: () => (
<SelectPanel
ref={selectPanelRef}
{...picker(props, [
'size',
'multiple',
Expand Down
Loading

0 comments on commit a78aa9d

Please sign in to comment.