@opensig/opendesign
Version:
221 lines (220 loc) • 7.09 kB
JavaScript
import { easeInOutCubic } from "./easing.mjs";
import { throttleRAF } from "./helper.mjs";
import { isWindow, isFunction } from "./is.mjs";
function isDocument(val) {
return val instanceof Document || (val == null ? void 0 : val.constructor.name) === "HTMLDocument";
}
function isHtmlElement(el) {
if (typeof HTMLElement === "object") {
return el instanceof HTMLElement;
} else if (el && typeof el === "object") {
const ele = el;
return (ele.nodeType === 1 || ele.nodeType === 9) && typeof ele.nodeName === "string";
}
return false;
}
function getOffsetElement(el) {
const offsetEl = el.offsetParent;
if (offsetEl && offsetEl.tagName === "BODY") {
const stylePosition = window.getComputedStyle(document.body).getPropertyValue("position");
if (stylePosition === "static") {
return document.documentElement;
}
}
return offsetEl;
}
function getScroll(el) {
const rlt = {
scrollLeft: 0,
scrollTop: 0
};
if (!el) {
return rlt;
}
if (isWindow(el)) {
rlt.scrollLeft = window.scrollX;
rlt.scrollTop = window.scrollY;
} else if (isDocument(el)) {
rlt.scrollLeft = el.documentElement.scrollLeft;
rlt.scrollTop = el.documentElement.scrollTop;
} else {
rlt.scrollLeft = el.scrollLeft;
rlt.scrollTop = el.scrollTop;
}
return rlt;
}
function getScrollParents(el) {
const parents = [];
let ele = el == null ? void 0 : el.parentElement;
while (ele && ele !== document.documentElement) {
const { offsetHeight, offsetWidth, scrollHeight, scrollWidth } = ele;
if (offsetHeight < scrollHeight || offsetWidth < scrollWidth) {
parents.push(ele);
}
ele = ele.parentElement;
}
return parents;
}
function findClosestElementWithClass(target, className, rootContainer) {
if (!(target instanceof HTMLElement)) {
return null;
}
let currentElement = target;
while (currentElement && currentElement !== rootContainer) {
if (currentElement.classList && currentElement.classList.contains(className)) {
return currentElement;
}
currentElement = currentElement.parentElement;
}
return null;
}
function getElementSize(el) {
return {
width: el.innerWidth || el.clientWidth,
height: el.innerHeight || el.clientHeight,
offsetWidth: el.innerWidth || el.offsetWidth,
offsetHeight: el.innerHeight || el.offsetHeight
};
}
function getElementRectByRAF(el) {
return new Promise((resolve) => {
const checkLayout = () => {
const rect = el.getBoundingClientRect();
if (rect.width > 0 || rect.height > 0) {
resolve(rect);
} else {
requestAnimationFrame(checkLayout);
}
};
requestAnimationFrame(checkLayout);
});
}
function getCssVariable(key, el) {
const ele = el ? el : document.documentElement;
return window.getComputedStyle(ele).getPropertyValue(key);
}
function supportTouch() {
return "ontouchstart" in window;
}
let cancelScrollRAF = null;
function scrollTo(y, opts) {
const { container = window, duration = 450 } = opts;
const { scrollTop } = getScroll(container);
const startTime = Date.now();
if (isFunction(cancelScrollRAF)) {
cancelScrollRAF();
cancelScrollRAF = null;
}
return new Promise((resolve) => {
const frameFn = () => {
const timeStamp = Date.now();
const time = timeStamp - startTime;
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
if (isWindow(container)) {
window.scrollTo({
left: window.scrollX,
top: nextScrollTop,
behavior: "instant"
});
} else if (isDocument(container)) {
container.documentElement.scrollTop = nextScrollTop;
} else {
container.scrollTop = nextScrollTop;
}
if (time < duration) {
const fn = throttleRAF(frameFn);
cancelScrollRAF = fn.cancel;
fn();
} else {
throttleRAF(resolve)();
}
};
throttleRAF(frameFn)();
});
}
function isOverflown(element) {
if (!element) {
return false;
}
return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
}
function checkElementOverflowHorizontal(options) {
const { element, parentElement, threshold = 0 } = options;
if (!(element instanceof HTMLElement)) {
throw new Error("参数必须是有效的HTMLElement");
}
const scrollParent = parentElement ? parentElement : getScrollParents(element)[0];
if (!scrollParent) {
return {
isOverflowLeft: false,
isOverflowRight: false,
overflowLeft: 0,
overflowRight: 0
};
}
const elementRect = element.getBoundingClientRect();
const parentRect = scrollParent.getBoundingClientRect();
const elementLeftRelativeToParent = elementRect.left - parentRect.left + scrollParent.scrollLeft;
const elementRightRelativeToParent = elementLeftRelativeToParent + elementRect.width;
const parentVisibleLeft = scrollParent.scrollLeft;
const parentVisibleRight = scrollParent.scrollLeft + scrollParent.clientWidth;
const overflowLeft = parentVisibleLeft - elementLeftRelativeToParent;
const isOverflowLeft = overflowLeft > threshold;
const overflowRight = elementRightRelativeToParent - parentVisibleRight;
const isOverflowRight = overflowRight > threshold;
return { isOverflowLeft, isOverflowRight, overflowLeft, overflowRight };
}
function checkElementOverflowVertical(options) {
const { element, parentElement, threshold = 0 } = options;
if (!(element instanceof HTMLElement)) {
throw new Error("参数必须是有效的HTMLElement");
}
const scrollParent = parentElement ? parentElement : getScrollParents(element)[0];
if (!scrollParent) {
return {
isOverflowTop: false,
isOverflowBottom: false,
overflowTop: 0,
overflowBottom: 0
};
}
const elementRect = element.getBoundingClientRect();
const parentRect = scrollParent.getBoundingClientRect();
const elementTopRelativeToParent = elementRect.top - parentRect.top + scrollParent.scrollTop;
const elementBottomRelativeToParent = elementTopRelativeToParent + elementRect.height;
const parentVisibleTop = scrollParent.scrollTop;
const parentVisibleBottom = scrollParent.scrollTop + scrollParent.clientHeight;
const overflowTop = parentVisibleTop - elementTopRelativeToParent;
const isOverflowTop = overflowTop > threshold;
const overflowBottom = elementBottomRelativeToParent - parentVisibleBottom;
const isOverflowBottom = overflowBottom > threshold;
return {
isOverflowTop,
isOverflowBottom,
overflowTop,
overflowBottom
};
}
function checkElementOverflow(options) {
return {
...checkElementOverflowHorizontal(options),
...checkElementOverflowVertical(options)
};
}
export {
checkElementOverflow,
checkElementOverflowHorizontal,
checkElementOverflowVertical,
findClosestElementWithClass,
getCssVariable,
getElementRectByRAF,
getElementSize,
getOffsetElement,
getScroll,
getScrollParents,
isDocument,
isHtmlElement,
isOverflown,
scrollTo,
supportTouch
};