UNPKG

@fe6/water-pro

Version:

An enterprise-class UI design language and Vue-based implementation

266 lines (235 loc) 7.21 kB
/** @format */ import { firstCapitalize } from '@fe6/shared'; import warning from './warning'; import ResizeObserver from 'resize-observer-polyfill'; export interface ViewportOffsetResult { left: number; top: number; right: number; bottom: number; rightIncludeBody: number; bottomIncludeBody: number; } export function getBoundingClientRect(element: Element): DOMRect | number { if (!element || !element.getBoundingClientRect) { return 0; } return element.getBoundingClientRect(); } const trim = function (string: string) { return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, ''); }; /* istanbul ignore next */ export function hasClass(el: Element, cls: string) { if (!el || !cls) { return false; } if (cls.includes(' ')) { throw warning('className 不应包含空格'); } if (el.classList) { return el.classList.contains(cls); } else { return ` ${el.className} `.includes(` ${cls} `); } } /* istanbul ignore next */ export function addClass(el: Element, cls: string) { if (!el) { return; } let curClass = el.className; const classes = (cls || '').split(' '); for (let i = 0, j = classes.length; i < j; i++) { const clsName = classes[i]; if (!clsName) { continue; } if (el.classList) { el.classList.add(clsName); } else if (!hasClass(el, clsName)) { curClass += ` ${clsName}`; } } if (!el.classList) { el.className = curClass; } } /* istanbul ignore next */ export function removeClass(el: Element, cls: string) { if (!el || !cls) { return; } const classes = cls.split(' '); let curClass = ` ${el.className} `; for (let i = 0, j = classes.length; i < j; i++) { const clsName = classes[i]; if (!clsName) { continue; } if (el.classList) { el.classList.remove(clsName); } else if (hasClass(el, clsName)) { curClass = curClass.replace(` ${clsName} `, ' '); } } if (!el.classList) { el.className = trim(curClass); } } /** * Get the left and top offset of the current element * left: the distance between the leftmost element and the left side of the document * top: the distance from the top of the element to the top of the document * right: the distance from the far right of the element to the right of the document * bottom: the distance from the bottom of the element to the bottom of the document * rightIncludeBody: the distance between the leftmost element and the right side of the document * bottomIncludeBody: the distance from the bottom of the element to the bottom of the document * * @description: */ export function getViewportOffset(element: Element): ViewportOffsetResult { const doc = document.documentElement; const docScrollLeft = doc.scrollLeft; const docScrollTop = doc.scrollTop; const docClientLeft = doc.clientLeft; const docClientTop = doc.clientTop; const pageXOffset = window.pageXOffset; const pageYOffset = window.pageYOffset; const box = getBoundingClientRect(element); const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect; const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0); const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0); const offsetLeft = retLeft + pageXOffset; const offsetTop = rectTop + pageYOffset; const left = offsetLeft - scrollLeft; const top = offsetTop - scrollTop; const clientWidth = window.document.documentElement.clientWidth; const clientHeight = window.document.documentElement.clientHeight; return { left, top, right: clientWidth - rectWidth - left, bottom: clientHeight - rectHeight - top, rightIncludeBody: clientWidth - left, bottomIncludeBody: clientHeight - top, }; } export function hackCss(attr: string, value: string) { const prefix: string[] = ['webkit', 'Moz', 'ms', 'OT']; const styleObj: any = {}; prefix.forEach((item) => { styleObj[`${item}${firstCapitalize(attr)}`] = value; }); return { ...styleObj, [attr]: value, }; } /* istanbul ignore next */ export function on( element: Element | HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject, ): void { if (element && event && handler) { element.addEventListener(event, handler, false); } } /* istanbul ignore next */ export function off( element: Element | HTMLElement | Document | Window, event: string, handler: Fn, ): void { if (element && event && handler) { element.removeEventListener(event, handler, false); } } /* istanbul ignore next */ export function once(el: HTMLElement, event: string, fn: EventListener): void { const listener = function (this: any, ...args: unknown[]) { if (fn) { fn.apply(this, args as any); } off(el, event, listener); }; on(el, event, listener); } /** * triggter window.resize */ export function triggerWindowResize() { const event = document.createEvent('HTMLEvents'); event.initEvent('resize', true, true); (event as any).eventType = 'message'; window.dispatchEvent(event); } /** * @description: Set ui mount node */ export function getPopupContainer(node?: HTMLElement): HTMLElement { return (node?.parentNode as HTMLElement) ?? document.body; } export const isServer = typeof window === 'undefined'; /* istanbul ignore next */ function resizeHandler(entries: any[]) { for (const entry of entries) { const listeners = entry.target.__resizeListeners__ || []; if (listeners.length) { listeners.forEach((fn: () => any) => { fn(); }); } } } /* istanbul ignore next */ export function addResizeListener(element: any, fn: () => any) { if (isServer) { return; } if (!element.__resizeListeners__) { element.__resizeListeners__ = []; element.__ro__ = new ResizeObserver(resizeHandler); element.__ro__.observe(element); } element.__resizeListeners__.push(fn); } /* istanbul ignore next */ export function removeResizeListener(element: any, fn: () => any) { if (!element || !element.__resizeListeners__) { return; } element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); if (!element.__resizeListeners__.length) { element.__ro__.disconnect(); } } export const getCursortPositionFormTextArea = (ctrl: any) => { const CaretPos = { start: 0, end: 0, }; if (ctrl.selectionStart) { // Firefox support CaretPos.start = ctrl.selectionStart; } if (ctrl.selectionEnd) { CaretPos.end = ctrl.selectionEnd; } return CaretPos; }; // 设置光标位置 export function setCaretPosition(ctrl: any, pos: number) { // 设置光标位置函数 if (ctrl.setSelectionRange) { ctrl.focus(); // 获取焦点 ctrl.setSelectionRange(pos, pos); // 设置选定区的开始和结束点 } else if (ctrl.createTextRange) { const range = ctrl.createTextRange(); // 创建选定区 range.collapse(true); // 设置为折叠,即光标起点和结束点重叠在一起 range.moveEnd('character', pos); // 移动结束点 range.moveStart('character', pos); // 移动开始点 range.select(); // 选定当前区域 } }