UNPKG

vxe-table

Version:

A PC-end table component based on Vxe UI, supporting copy-paste, data pivot table, and high-performance virtual list table solution.

413 lines (412 loc) 14.5 kB
import XEUtils from 'xe-utils'; const reClsMap = {}; let tpImgEl; export function initTpImg() { if (!tpImgEl) { tpImgEl = new Image(); tpImgEl.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; } return tpImgEl; } export function getTpImg() { if (!tpImgEl) { return initTpImg(); } return tpImgEl; } export function getPropClass(property, params) { return property ? (XEUtils.isFunction(property) ? property(params) : property) || '' : ''; } function getClsRE(cls) { if (!reClsMap[cls]) { reClsMap[cls] = new RegExp(`(?:^|\\s)${cls}(?!\\S)`, 'g'); } return reClsMap[cls]; } function getNodeOffset(elem, container, rest) { if (elem) { const parentElem = elem.parentNode; rest.top += elem.offsetTop; rest.left += elem.offsetLeft; if (parentElem && parentElem !== document.documentElement && parentElem !== document.body) { rest.top -= parentElem.scrollTop; rest.left -= parentElem.scrollLeft; } if (container && (elem === container || elem.offsetParent === container) ? 0 : elem.offsetParent) { return getNodeOffset(elem.offsetParent, container, rest); } } return rest; } export function isPx(val) { return val && /^\d+(\.\d+)?(px)?$/.test(val); } export function isScale(val) { return val && /^\d+(\.\d+)?%$/.test(val); } export function hasClass(elem, cls) { if (elem) { if (elem.classList) { return elem.classList.contains(cls); } return !!(elem.className && elem.className.match && elem.className.match(getClsRE(cls))); } return false; } export function removeClass(elem, cls) { if (elem && hasClass(elem, cls)) { elem.className = elem.className.replace(getClsRE(cls), ''); } } export function addClass(elem, cls) { if (elem && !hasClass(elem, cls)) { removeClass(elem, cls); elem.className = `${elem.className} ${cls}`; } } export function hasControlKey(evnt) { return evnt.ctrlKey || evnt.metaKey; } export function toCssUnit(val, unit = 'px') { if (XEUtils.isNumber(val) || /^\d+$/.test(`${val}`)) { return `${val}${unit}`; } return `${val || ''}`; } export function queryElement(elem, selector) { if (elem) { return elem.querySelector(selector); } return null; } export function getDomNode() { const documentElement = document.documentElement; const bodyElem = document.body; return { scrollTop: documentElement.scrollTop || bodyElem.scrollTop, scrollLeft: documentElement.scrollLeft || bodyElem.scrollLeft, visibleHeight: documentElement.clientHeight || bodyElem.clientHeight, visibleWidth: documentElement.clientWidth || bodyElem.clientWidth }; } export function getOffsetHeight(elem) { return elem ? elem.offsetHeight : 0; } export function getPaddingTopBottomSize(elem) { if (elem) { const computedStyle = getComputedStyle(elem); const paddingTop = XEUtils.toNumber(computedStyle.paddingTop); const paddingBottom = XEUtils.toNumber(computedStyle.paddingBottom); return paddingTop + paddingBottom; } return 0; } export function setScrollTop(elem, scrollTop) { if (elem) { elem.scrollTop = scrollTop; } } export function setScrollLeft(elem, scrollLeft) { if (elem) { elem.scrollLeft = scrollLeft; } } // export function setScrollLeftAndTop (elem: HTMLElement | null, scrollLeft: number, scrollTop: number) { // if (elem) { // elem.scrollLeft = scrollLeft // elem.scrollTop = scrollTop // } // } export function updateCellTitle(overflowElem, column) { const content = column.type === 'html' ? overflowElem.innerText : overflowElem.textContent; if (overflowElem.getAttribute('title') !== content) { overflowElem.setAttribute('title', content); } } export function checkTargetElement(target, exEls, endEl) { let targetEl = target; if (!exEls || !exEls.length) { return false; } const [exEl1, exEl2, exEl3] = exEls; while (targetEl) { if (exEl1 === targetEl || (exEl2 && targetEl === exEl2) || (exEl3 && targetEl === exEl3)) { return true; } if (endEl && targetEl === endEl) { return false; } targetEl = targetEl.parentElement; } return false; } /** * 检查触发源是否属于目标节点 */ export function getEventTargetNode(evnt, container, queryCls, queryMethod) { let targetElem; let target = (evnt.target.shadowRoot && evnt.composed) ? (evnt.composedPath()[0] || evnt.target) : evnt.target; while (target && target.nodeType && target !== document) { if (queryCls && hasClass(target, queryCls) && (!queryMethod || queryMethod(target))) { targetElem = target; } else if (target === container) { return { flag: queryCls ? !!targetElem : true, container, targetElem: targetElem }; } target = target.parentNode; } return { flag: false }; } /** * 获取元素相对于 document 的位置 */ export function getOffsetPos(elem, container) { return getNodeOffset(elem, container, { left: 0, top: 0 }); } export function getAbsolutePos(elem) { const bounding = elem.getBoundingClientRect(); const boundingTop = bounding.top; const boundingLeft = bounding.left; const { scrollTop, scrollLeft, visibleHeight, visibleWidth } = getDomNode(); return { boundingTop, top: scrollTop + boundingTop, boundingLeft, left: scrollLeft + boundingLeft, visibleHeight, visibleWidth }; } export function hasEventInputTarget(target) { const tagName = target ? target.tagName : ''; return tagName && ['input', 'textarea'].includes((tagName.toLowerCase())); } /** * 判断是否由内部可复用控件触发,输入框带有 vxe-reusekeep-control */ function hasReusekeepControl(elem) { if (elem) { return hasClass(elem, 'vxe-reusekeep-control'); } return false; } export function hasAxternalInputTarget(target) { return hasEventInputTarget(target) ? !hasReusekeepControl(target) : false; } const scrollIntoViewIfNeeded = 'scrollIntoViewIfNeeded'; const scrollIntoView = 'scrollIntoView'; export function scrollToView(elem) { if (elem) { if (elem[scrollIntoViewIfNeeded]) { elem[scrollIntoViewIfNeeded](); } else if (elem[scrollIntoView]) { elem[scrollIntoView](); } } } export function triggerEvent(targetElem, type) { if (targetElem) { targetElem.dispatchEvent(new Event(type)); } } export function isNodeElement(elem) { return elem && elem.nodeType === 1; } export function scrollTopTo(diffNum, cb) { const duration = Math.abs(diffNum); const startTime = performance.now(); let countTop = 0; const step = (timestamp) => { let progress = (timestamp - startTime) / duration; if (progress < 0) { progress = 0; } else if (progress > 1) { progress = 1; } const easedProgress = Math.pow(progress, 2); const offsetTop = Math.floor((diffNum * easedProgress)) - countTop; countTop += offsetTop; cb(offsetTop); if (progress < 1) { requestAnimationFrame(step); } }; requestAnimationFrame(step); } let wtlFrame; export function wheelScrollLeftTo(scrollLeft, cb) { if (wtlFrame) { cancelAnimationFrame(wtlFrame); } wtlFrame = requestAnimationFrame(() => { cb(scrollLeft); wtlFrame = null; }); } let wtaFrame; export function wheelScrollTopTo(diffNum, cb) { if (wtaFrame) { cancelAnimationFrame(wtaFrame); } wtaFrame = requestAnimationFrame(() => { const offsetTop = diffNum; cb(offsetTop); wtaFrame = null; }); } /** * 通用定位计算 */ export function updatePanelPlacement(targetElem, panelElem, options) { const { defaultTop, defaultLeft, placement, defaultPlacement, teleportTo, marginSize, isMinWidth } = Object.assign({ teleportTo: false, marginSize: 18, isMinWidth: true }, options); let panelPlacement = 'bottom'; let top = ''; let bottom = ''; let left = 0; let minWidth = ''; let arrowLeft = ''; const stys = {}; if (panelElem && targetElem) { const bodyEl = document.body; const parentWrapperEl = getPopupWrapperElement(panelElem); if (parentWrapperEl) { const targetWidth = targetElem.offsetWidth; const targetHeight = targetElem.offsetHeight; const panelWidth = panelElem.offsetWidth; const panelHeight = panelElem.offsetHeight; const parentWrapperRect = parentWrapperEl.getBoundingClientRect(); const panelRect = panelElem.getBoundingClientRect(); const targetRect = targetElem.getBoundingClientRect(); const visibleHeight = bodyEl.clientHeight; const visibleWidth = bodyEl.clientWidth; const offsetLeft = parentWrapperRect.left; const offsetTop = parentWrapperRect.top; const targetLeft = targetRect.left; const targetTop = targetRect.top; minWidth = targetElem.offsetWidth; if (teleportTo) { left = defaultLeft || (targetLeft - (panelWidth - targetWidth) / 2); top = defaultTop || (targetTop + targetHeight); if (placement === 'top') { panelPlacement = 'top'; top = targetTop - panelHeight; } else if (!placement) { if (defaultPlacement === 'top') { panelPlacement = 'top'; if (!defaultTop) { top = targetTop - panelHeight; } // 如果上面不够放,则向下 if (top < marginSize) { panelPlacement = 'bottom'; top = targetTop + targetHeight; } // 如果下面不够放,则向上(优先) if (top + panelHeight + marginSize > visibleHeight) { panelPlacement = 'top'; top = targetTop - panelHeight; } } else { // 如果下面不够放,则向上 if (top + panelHeight + marginSize > visibleHeight) { panelPlacement = 'top'; top = targetTop - panelHeight; } // 如果上面不够放,则向下(优先) if (top < marginSize) { panelPlacement = 'bottom'; top = targetTop + targetHeight; } } } // 如果溢出右边 if (left + panelWidth + marginSize > visibleWidth) { left -= left + panelWidth + marginSize - visibleWidth; } // 如果溢出左边 if (left < marginSize) { left = marginSize; } // 偏移 top -= offsetTop; left -= offsetLeft; } else { if (placement === 'top') { panelPlacement = 'top'; bottom = targetHeight; } else if (!placement) { // 如果下面不够放,则向上 top = targetHeight; if (targetTop + targetHeight + panelHeight + marginSize > visibleHeight) { // 如果上面不够放,则向下(优先) if (targetTop - targetHeight - panelHeight > marginSize) { panelPlacement = 'top'; top = ''; bottom = targetHeight; } } } // 是否超出右侧 if (panelRect.left + panelRect.width + marginSize > visibleWidth) { left = -(panelRect.left + panelRect.width + marginSize - visibleWidth); } } if (XEUtils.isNumber(top)) { stys.top = toCssUnit(top); } if (XEUtils.isNumber(bottom)) { stys.bottom = toCssUnit(bottom); } if (XEUtils.isNumber(left)) { stys.left = toCssUnit(left); } if (isMinWidth && XEUtils.isNumber(minWidth)) { stys.minWidth = toCssUnit(minWidth); } // 箭头 if (left === targetLeft) { if (targetWidth <= panelWidth) { arrowLeft = targetWidth / 2; } } else if (left < targetLeft) { if (left + panelWidth > targetLeft + targetWidth) { arrowLeft = (targetLeft - left) + targetWidth / 2; } else { arrowLeft = (targetLeft - left) + (panelWidth - (targetLeft - left)) / 2; } } } } return { top: top || 0, bottom: bottom || 0, left: left || 0, arrowLeft: arrowLeft || 0, style: stys, placement: panelPlacement }; } export function getPopupWrapperElement(panelElem) { if (!panelElem) { return null; } const bodyEl = document.body; const parentEl = panelElem.parentElement; return (parentEl === bodyEl ? document.documentElement : parentEl) || null; } export function getPopupContainer(appendTo) { const selectElem = appendTo && XEUtils.isFunction(appendTo) ? appendTo({}) : appendTo; return selectElem || 'body'; } export function getPopupAppendElement(appendTo) { const selectElem = getPopupContainer(appendTo); if (XEUtils.isString(selectElem)) { return document.querySelector(selectElem) || document.body; } return selectElem; }