gtht-miniapp-sdk
Version:
gtht-miniapp-sdk 是一套基于 Uniapp + Vue3 框架开发的兼容多端的 UI 组件库
129 lines (128 loc) • 4.48 kB
JavaScript
import { getWindowInfo, clamp } from '../../utils';
const directions = ['top', 'right', 'bottom', 'left'];
function getReverseDirection(direction) {
const index = directions.indexOf(direction);
return directions[index + 2] ?? directions[index - 2];
}
function getAxis(direction) {
return ['top', 'bottom'].includes(direction) ? 'left' : 'top';
}
function getCrossAxis(axis) {
return axis === 'top' ? 'left' : 'top';
}
function getSizeNameByAxis(axis) {
return axis === 'top' ? 'height' : 'width';
}
function getArrowCrossOffset(direction, rect) {
const strategies = {
top() {
return rect.height;
},
right() {
return 0;
},
bottom() {
return 0;
},
left() {
return rect.width;
},
};
return strategies[direction]();
}
export function getPopoverPosition(refRect, popperRect, { refGap, position, viewportGap, arrowSize, }) {
const breadth = popperRect.width + refGap;
const thickness = popperRect.height + refGap;
const { windowWidth, windowHeight } = getWindowInfo();
const gapBoundaries = {
top: refRect.top - thickness - viewportGap,
right: windowWidth - refRect.right - breadth - viewportGap,
bottom: windowHeight - refRect.bottom - thickness - viewportGap,
left: refRect.left - breadth - viewportGap,
};
// 确定方位
let [direction, side] = position.split('-');
// 适当反转
if (gapBoundaries[direction] < 0) {
direction = getReverseDirection(direction);
if (gapBoundaries[direction] < 0) {
direction = getReverseDirection(direction);
}
}
// 确定端点
side = side || 'center';
// 确定轴
const axis = getAxis(direction);
const crossAxis = getCrossAxis(axis);
// 确定尺寸
const axisSizeName = getSizeNameByAxis(axis);
const crossAxisSizeName = getSizeNameByAxis(crossAxis);
const axisWindowSize = axis === 'top' ? windowHeight : windowWidth;
const crossAxisWindowSize = axis === 'top' ? windowWidth : windowHeight;
const popperStyle = {
top: 0,
left: 0,
};
function getSideOffset() {
const strategies = {
start() {
return refRect[axis];
},
center() {
return (refRect[axis] - (popperRect[axisSizeName] - refRect[axisSizeName]) / 2);
},
end() {
return (refRect[axis] - (popperRect[axisSizeName] - refRect[axisSizeName]));
},
};
const offset = strategies[side]();
// 确保处于屏幕内
return clamp(offset, viewportGap, axisWindowSize - popperRect[axisSizeName] - viewportGap);
}
function getDirectionOffset() {
const strategies = {
top() {
return refRect.top - refGap - popperRect.height;
},
right() {
return refRect.right + refGap;
},
bottom() {
return refRect.bottom + refGap;
},
left() {
return refRect.left - refGap - popperRect.width;
},
};
const offset = strategies[direction]();
// 确保处于屏幕内
return clamp(offset, viewportGap, crossAxisWindowSize - popperRect[crossAxisSizeName] - viewportGap);
}
popperStyle[crossAxis] = getDirectionOffset();
popperStyle[axis] = getSideOffset();
const finalPopperRect = {
top: popperStyle.top,
left: popperStyle.left,
bottom: popperStyle.top + popperRect.height,
right: popperStyle.left + popperRect.width,
};
const arrowStyle = {
top: 0,
left: 0,
};
function getArrowOffset() {
const reverseDirection = getReverseDirection(axis);
let extra = refRect[axis] - finalPopperRect[axis];
if (extra < 0) {
extra = 0;
}
const intersection = Math.min(refRect[reverseDirection], finalPopperRect[reverseDirection]) -
Math.max(refRect[axis], finalPopperRect[axis]);
const offset = extra + intersection / 2;
// 确保箭头位于popper之内
return clamp(offset, arrowSize, popperRect[axisSizeName] - arrowSize);
}
arrowStyle[axis] = getArrowOffset();
arrowStyle[crossAxis] = getArrowCrossOffset(direction, popperRect);
return [popperStyle, arrowStyle];
}