25 lines
2.0 KiB
TypeScript
25 lines
2.0 KiB
TypeScript
/*** 浮层上下翻转判定:按触发器与面板的视口几何判断首选方位是否放得下,放不下且另一侧更宽敞则翻转;返回实际生效方位 'top' | 'bottom' ***/
|
||
export function flip(trigger: HTMLElement, panel: HTMLElement, preferred: 'top' | 'bottom'): 'top' | 'bottom' {
|
||
const GAP = 8; // 与 CSS 预留的浮层间距一致(popover 为 8px)
|
||
const MIN = 24; // 兜底:面板尚未量出高度时按最小可读高度估算
|
||
const t = trigger.getBoundingClientRect(); // 触发器视口矩形
|
||
const h = panel.offsetHeight || MIN; // 面板高度(visibility:hidden 仍占布局,可直接量)
|
||
const up = t.top; // 触发器上方可用空间
|
||
const down = window.innerHeight - t.bottom; // 触发器下方可用空间
|
||
if (preferred === 'top') return up >= h + GAP || up >= down ? 'top' : 'bottom'; // 首选上方:放得下、或不比下方更局促就保持
|
||
return down >= h + GAP || down >= up ? 'bottom' : 'top'; // 首选下方:对称判定
|
||
}
|
||
|
||
/*** 浮层方位判定(四向):水平方向按宽度判左右空间,垂直方向复用 flip 的上下一套逻辑 ***/
|
||
export function flipSide(trigger: HTMLElement, panel: HTMLElement, preferred: 'top' | 'bottom' | 'left' | 'right'): 'top' | 'bottom' | 'left' | 'right' {
|
||
const GAP = 8; // 与样式表预留的间距一致
|
||
const MIN = 24; // 兜底:面板尚未量出宽度时按最小可读宽度估算
|
||
if (preferred === 'top' || preferred === 'bottom') return flip(trigger, panel, preferred); // 垂直交回原判定
|
||
const t = trigger.getBoundingClientRect();
|
||
const w = panel.offsetWidth || MIN;
|
||
const left = t.left; // 触发器左侧可用空间
|
||
const right = window.innerWidth - t.right; // 触发器右侧可用空间
|
||
if (preferred === 'left') return left >= w + GAP || left >= right ? 'left' : 'right'; // 对称判定
|
||
return right >= w + GAP || right >= left ? 'right' : 'left';
|
||
}
|