import { UNICODE_SYMBOL_REG } from '../dataset/constant/Regular' export function debounce( func: (...arg: T) => unknown, delay: number ) { let timer: number return function (this: unknown, ...args: T) { if (timer) { window.clearTimeout(timer) } timer = window.setTimeout(() => { func.apply(this, args) }, delay) } } export function throttle( func: (...arg: T) => unknown, delay: number ) { let lastExecTime = 0 let timer: number return function (this: unknown, ...args: T) { const currentTime = Date.now() if (currentTime - lastExecTime >= delay) { window.clearTimeout(timer) func.apply(this, args) lastExecTime = currentTime } else { window.clearTimeout(timer) timer = window.setTimeout(() => { func.apply(this, args) lastExecTime = currentTime }, delay) } } } export function deepCloneOmitKeys(obj: T, omitKeys: (keyof K)[]): T { if (!obj || typeof obj !== 'object') { return obj } let newObj: any = {} if (Array.isArray(obj)) { newObj = obj.map(item => deepCloneOmitKeys(item, omitKeys)) } else { // prettier-ignore (Object.keys(obj) as (keyof K)[]).forEach(key => { if (omitKeys.includes(key)) return return (newObj[key] = deepCloneOmitKeys((obj[key as unknown as keyof T] ), omitKeys)) }) } return newObj } export function deepClone(obj: T): T { if (!obj || typeof obj !== 'object') { return obj } let newObj: any = {} if (Array.isArray(obj)) { newObj = obj.map(item => deepClone(item)) } else { // prettier-ignore (Object.keys(obj) as (keyof T)[]).forEach(key => { return (newObj[key] = deepClone(obj[key])) }) } return newObj } export function isBody(node: Element): boolean { return node && node.nodeType === 1 && node.tagName.toLowerCase() === 'body' } export function findParent( node: Element, filterFn: Function, includeSelf: boolean ) { if (node && !isBody(node)) { node = includeSelf ? node : (node.parentNode as Element) while (node) { if (!filterFn || filterFn(node) || isBody(node)) { return filterFn && !filterFn(node) && isBody(node) ? null : node } node = node.parentNode as Element } } return null } export function getUUID(): string { function S4(): string { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1) } return ( S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4() ) } export function splitText(text: string): string[] { const data: string[] = [] if (Intl.Segmenter) { const segmenter = new Intl.Segmenter() const segments = segmenter.segment(text) for (const { segment } of segments) { data.push(segment) } } else { const symbolMap = new Map() for (const match of text.matchAll(UNICODE_SYMBOL_REG)) { symbolMap.set(match.index!, match[0]) } let t = 0 while (t < text.length) { const symbol = symbolMap.get(t) if (symbol) { data.push(symbol) t += symbol.length } else { data.push(text[t]) t++ } } } return data } export function downloadFile(href: string, fileName: string) { const a = document.createElement('a') a.href = href a.download = fileName a.click() } export function threeClick(dom: HTMLElement, fn: (evt: MouseEvent) => any) { nClickEvent(3, dom, fn) } function nClickEvent( n: number, dom: HTMLElement, fn: (evt: MouseEvent) => any ) { let count = 0 let lastTime = 0 const handler = function (evt: MouseEvent) { const currentTime = new Date().getTime() count = currentTime - lastTime < 300 ? count + 1 : 0 lastTime = new Date().getTime() if (count >= n - 1) { fn(evt) count = 0 } } dom.addEventListener('click', handler) } export function isObject(type: unknown): type is Record { return Object.prototype.toString.call(type) === '[object Object]' } export function isArray(type: unknown): type is Array { return Array.isArray(type) } export function mergeObject(source: T, target: T): T { if (isObject(source) && isObject(target)) { const objectTarget = >target for (const [key, val] of Object.entries(source)) { if (!objectTarget[key]) { objectTarget[key] = val } else { objectTarget[key] = mergeObject(val, objectTarget[key]) } } } else if (isArray(source) && isArray(target)) { target.push(...source) } return target } export function nextTick(fn: Function) { setTimeout(() => { fn() }, 0) } export function convertNumberToChinese(num: number) { const chineseNum = [ '零', '一', '二', '三', '四', '五', '六', '七', '八', '九' ] const chineseUnit = [ '', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万', '十', '百', '千', '亿' ] if (!num || isNaN(num)) return '零' const numStr = num.toString().split('') let result = '' for (let i = 0; i < numStr.length; i++) { const desIndex = numStr.length - 1 - i result = `${chineseUnit[i]}${result}` result = `${chineseNum[Number(numStr[desIndex])]}${result}` } result = result.replace(/零(千|百|十)/g, '零').replace(/十零/g, '十') result = result.replace(/零+/g, '零') result = result.replace(/零亿/g, '亿').replace(/零万/g, '万') result = result.replace(/亿万/g, '亿') result = result.replace(/零+$/, '') result = result.replace(/^一十/g, '十') return result } export function cloneProperty( properties: (keyof T)[], sourceElement: T, targetElement: T ) { for (let i = 0; i < properties.length; i++) { const property = properties[i] const value = sourceElement[property] if (value !== undefined) { targetElement[property] = value } else { delete targetElement[property] } } } export function pickObject(object: T, pickKeys: (keyof T)[]): T { const newObject: T = {} for (const key in object) { if (pickKeys.includes(key)) { newObject[key] = object[key] } } return newObject } export function omitObject(object: T, omitKeys: (keyof T)[]): T { const newObject: T = {} for (const key in object) { if (!omitKeys.includes(key)) { newObject[key] = object[key] } } return newObject } export function convertStringToBase64(input: string) { const encoder = new TextEncoder() const data = encoder.encode(input) const charArray = Array.from(data, byte => String.fromCharCode(byte)) const base64 = window.btoa(charArray.join('')) return base64 } export function findScrollContainer(element: HTMLElement) { let parent = element.parentElement while (parent) { const style = window.getComputedStyle(parent) const overflowY = style.getPropertyValue('overflow-y') if ( parent.scrollHeight > parent.clientHeight && (overflowY === 'auto' || overflowY === 'scroll') ) { return parent } parent = parent.parentElement } return document.documentElement } export function isArrayEqual(arr1: unknown[], arr2: unknown[]): boolean { if (arr1.length !== arr2.length) { return false } return !arr1.some(item => !arr2.includes(item)) } export function isObjectEqual(obj1: unknown, obj2: unknown): boolean { if (!isObject(obj1) || !isObject(obj2)) return false const obj1Keys = Object.keys(obj1) const obj2Keys = Object.keys(obj2) if (obj1Keys.length !== obj2Keys.length) { return false } return !obj1Keys.some(key => obj2[key] !== obj1[key]) }