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

fix: refactor adjust implementation #22

Merged
merged 11 commits into from
Nov 23, 2023
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Popup 是对 Overlay 的封装,children作为触发节点,弹出一个浮层
| onRequestClose | 弹层请求关闭时触发事件的回调函数 | Function | () => {} |
| target | 弹层定位的参照元素 | Function | ()=> document.body |
| points | 弹层相对于参照元素的定位 | [point, point] | ['tl', 'bl'] |
| placement | 部分points的简写模式<br/><br/>**可选值**:<br/>'t'(上,对应 points: ['bc', 'tc'])<br/>'r'(右,对应 points: ['lc', 'rc'])<br/>'b'(下,对应 points: ['tc', 'bc'])<br/>'l'(左,对应 points: ['rc', 'lc'])<br/>'tl'(上左,对应 points: ['bl', 'tl'])<br/>'tr'(上右,对应 points: ['br', 'tr'])<br/>'bl'(下左,对应 points: ['tl', 'bl'])<br/>'br'(下右,对应 points: ['tr', 'br'])<br/>'lt'(左上,对应 points: ['rt', 'lt'])<br/>'lb'(左下,对应 points: ['rb', 'lb'])<br/>'rt'(右上,对应 points: ['lt', 'rt'])<br/>'rb'(右下,对应 points: ['lb', 'rb']) | Enum | 'bl' | |
| offset | 弹层相对于trigger的定位的微调, 接收数组[hoz, ver], 表示弹层在 left / top 上的增量<br/>e.g. [100, 100] 表示往右、下分布偏移100px | Array | [0, 0]|
| container | 渲染组件的容器,如果是函数需要返回 ref,如果是字符串则是该 DOM 的 id,也可以直接传入 DOM 节点 | any | - |
| hasMask | 是否显示遮罩 | Boolean | false |
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@alifd/next": "1.x",
"@commitlint/cli": "^8.3.6",
"@iceworks/spec": "^1.0.0",
"@types/jest": "^26.0.24",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.3",
Expand Down
22 changes: 17 additions & 5 deletions src/overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
getFocusNodeList,
isSameObject,
useEvent,
getWidthHeight,
} from './utils';
import OverlayContext from './overlay-context';

Expand Down Expand Up @@ -257,7 +258,7 @@ const Overlay = React.forwardRef<HTMLDivElement, OverlayProps>((props, ref) => {

if (!isSameObject(positionStyleRef.current, placements.style)) {
positionStyleRef.current = placements.style;
setStyle(overlayNode, placements.style);
setStyle(overlayNode, { ...placements.style, visibility: '' });
typeof onPosition === 'function' && onPosition(placements);
}
});
Expand All @@ -268,7 +269,6 @@ const Overlay = React.forwardRef<HTMLDivElement, OverlayProps>((props, ref) => {
const node = findDOMNode(nodeRef) as HTMLElement;
overlayRef.current = node;
callRef(ref, node);

if (node !== null && container) {
const containerNode = getRelativeContainer(getHTMLElement(container));
containerRef.current = containerNode;
Expand All @@ -285,13 +285,25 @@ const Overlay = React.forwardRef<HTMLDivElement, OverlayProps>((props, ref) => {
overflowRef.current = getOverflowNodes(targetNode, containerNode);

// 1. 这里提前先设置好 position 属性,因为有的节点可能会因为设置了 position 属性导致宽度变小
// 2. 提前设置 top/left -1000 先把弹窗藏起来,以免影响了 container 的高度计算
setStyle(node, { position: fixed ? 'fixed' : 'absolute', top: -1000, left: -1000 });
// 2. 设置 visibility 先把弹窗藏起来,避免影响视图
// 3. 因为未知原因,原先 left&top 设置为 -1000的方式隐藏会导致获取到的overlay元素宽高不对
// https://drafts.csswg.org/css-position/#abspos-layout 未在此处找到相关解释,可能是浏览器优化,但使其有部分在可视区域内,就可以获取到渲染后正确的宽高, 然后使用visibility隐藏
const nodeRect = getWidthHeight(node);
setStyle(node, {
position: fixed ? 'fixed' : 'absolute',
// 这里 -nodeRect.width 是避免添加到容器内导致容器出现宽高变化, +1 是为了能确保有一部分在可视区域内
top: -nodeRect.height + 1,
YSMJ1994 marked this conversation as resolved.
Show resolved Hide resolved
left: -nodeRect.width + 1,
visibility: 'hidden',
});

const waitTime = 100;
ro.current = new ResizeObserver(throttle(updatePosition.bind(this), waitTime));
const throttledUpdatePosition = throttle(updatePosition, waitTime);
ro.current = new ResizeObserver(throttledUpdatePosition);
ro.current.observe(containerNode);
ro.current.observe(node);
// fist call, 不依赖 ResizeObserver observe时的首次执行(测试环境不会执行),因为 throttle 原因也不会执行两次
throttledUpdatePosition();

forceUpdate({});

Expand Down
Loading