Skip to content

Commit 1b94da5

Browse files
authored
fix(Cascader): improve scroll behavior for selected nodes (#3772)
1 parent ec91d65 commit 1b94da5

File tree

1 file changed

+43
-21
lines changed

1 file changed

+43
-21
lines changed

packages/components/cascader/Cascader.tsx

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
import React, { useMemo } from 'react';
22
import classNames from 'classnames';
3-
import { pick, omit } from 'lodash-es';
4-
import Panel from './components/Panel';
5-
import SelectInput from '../select-input';
3+
import { omit, pick } from 'lodash-es';
4+
import parseTNode, { parseContentTNode } from '../_util/parseTNode';
65
import FakeArrow from '../common/FakeArrow';
7-
import useConfig from '../hooks/useConfig';
86
import useCommonClassName from '../hooks/useCommonClassName';
7+
import useConfig from '../hooks/useConfig';
8+
import useDefaultProps from '../hooks/useDefaultProps';
99
import { useLocaleReceiver } from '../locale/LocalReceiver';
10-
import { TagInputValue } from '../tag-input';
11-
import { TdCascaderProps } from './interface';
12-
import { closeIconClickEffect, handleRemoveTagEffect } from './core/effect';
13-
import { getPanels, getSingleContent, getMultipleContent } from './core/helper';
10+
import SelectInput from '../select-input';
11+
import Panel from './components/Panel';
1412
import { getFakeArrowIconClass } from './core/className';
15-
import { useCascaderContext } from './hooks';
13+
import { closeIconClickEffect, handleRemoveTagEffect } from './core/effect';
14+
import { getMultipleContent, getPanels, getSingleContent } from './core/helper';
1615
import { cascaderDefaultProps } from './defaultProps';
17-
import { StyledProps } from '../common';
18-
import useDefaultProps from '../hooks/useDefaultProps';
19-
import parseTNode, { parseContentTNode } from '../_util/parseTNode';
16+
import { useCascaderContext } from './hooks';
17+
18+
import type { StyledProps } from '../common';
19+
import type { TagInputValue } from '../tag-input';
20+
import type { TdCascaderProps } from './interface';
2021

2122
export interface CascaderProps extends TdCascaderProps, StyledProps {}
2223

@@ -106,19 +107,40 @@ const Cascader: React.FC<CascaderProps> = (originalProps) => {
106107
cascaderMenuList.forEach((menu: HTMLDivElement) => {
107108
const firstSelectedNode: HTMLDivElement =
108109
menu?.querySelector(`.${classPrefix}-is-selected`) || menu?.querySelector(`.${classPrefix}-is-expanded`);
110+
111+
// 只取第一个选中的节点进行滚动对齐
109112
if (!firstSelectedNode || !menu) return;
110113

111-
const { paddingBottom } = getComputedStyle(firstSelectedNode);
112-
const { marginBottom } = getComputedStyle(menu);
113-
const elementBottomHeight = parseInt(paddingBottom, 10) + parseInt(marginBottom, 10);
114+
// 计算节点在菜单中的相对位置
115+
const nodeTop = firstSelectedNode.offsetTop;
116+
const nodeHeight = firstSelectedNode.offsetHeight;
117+
const menuHeight = menu.clientHeight;
118+
const currentScrollTop = menu.scrollTop;
119+
120+
// 计算节点在可视区域中的位置
121+
const nodeVisibleTop = nodeTop - currentScrollTop;
122+
const nodeVisibleBottom = nodeVisibleTop + nodeHeight;
123+
124+
const isNodeFullyVisible = nodeVisibleTop >= 0 && nodeVisibleBottom <= menuHeight;
125+
// 如果节点已经完全可见,则不需要滚动
126+
if (isNodeFullyVisible) return;
127+
128+
let targetScrollTop = currentScrollTop;
129+
130+
if (nodeVisibleTop < 0) {
131+
// 如果节点在可视区域上方,滚动到节点顶部
132+
targetScrollTop = nodeTop;
133+
} else if (nodeVisibleBottom > menuHeight) {
134+
// 如果节点在可视区域下方,滚动到节点底部对齐菜单底部
135+
targetScrollTop = nodeTop - menuHeight + nodeHeight;
136+
}
137+
138+
// 确保滚动位置不会超出边界
139+
const maxScrollTop = menu.scrollHeight - menuHeight;
140+
targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
114141

115-
const updateValue =
116-
firstSelectedNode.offsetTop -
117-
menu.offsetTop -
118-
(menu.clientHeight - firstSelectedNode.clientHeight) +
119-
elementBottomHeight;
120142
// eslint-disable-next-line no-param-reassign
121-
menu.scrollTop = updateValue;
143+
menu.scrollTop = targetScrollTop;
122144
});
123145
});
124146
};

0 commit comments

Comments
 (0)