Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(select): 列表展开时定位置选中项 #1068

Merged
merged 4 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
},
PengYYYYY marked this conversation as resolved.
Show resolved Hide resolved
);
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