You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
7.7 KiB

import { UNICODE_SYMBOL_REG } from '../dataset/constant/Regular'
export function debounce<T extends unknown[]>(
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<T extends unknown[]>(
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<T, K>(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<T>(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<number, string>()
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<string, unknown> {
return Object.prototype.toString.call(type) === '[object Object]'
}
export function isArray(type: unknown): type is Array<unknown> {
return Array.isArray(type)
}
export function mergeObject<T>(source: T, target: T): T {
if (isObject(source) && isObject(target)) {
const objectTarget = <Record<string, unknown>>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<T>(
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<T>(object: T, pickKeys: (keyof T)[]): T {
const newObject: T = <T>{}
for (const key in object) {
if (pickKeys.includes(key)) {
newObject[key] = object[key]
}
}
return newObject
}
export function omitObject<T>(object: T, omitKeys: (keyof T)[]): T {
const newObject: T = <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])
}