element-plus/packages/utils/util.ts

283 lines
6.2 KiB
TypeScript
Raw Normal View History

import { getCurrentInstance } from 'vue'
import {
camelize,
capitalize,
extend,
hasOwn,
hyphenate,
isArray,
isObject,
isString,
isFunction,
looseEqual,
toRawType,
} from '@vue/shared'
import isEqualWith from 'lodash/isEqualWith'
2020-09-14 10:03:33 +08:00
import isServer from './isServer'
2021-01-28 22:10:45 +08:00
import { warn } from './error'
import type { ComponentPublicInstance, CSSProperties, Ref } from 'vue'
import type { AnyFunction, TimeoutHandle, Hash, Nullable } from './types'
// type polyfill for compat isIE method
declare global {
interface Document {
documentMode?: any
}
}
2021-01-28 22:10:45 +08:00
export const SCOPE = 'Util'
export function toObject<T>(arr: Array<T>): Record<string, T> {
const res = {}
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
}
export const getValueByPath = (obj, paths = ''): unknown => {
let ret: unknown = obj
paths.split('.').map((path) => {
ret = ret?.[path]
})
return ret
}
export function getPropByPath(
obj: any,
path: string,
strict: boolean
): {
2020-08-02 21:29:35 +08:00
o: unknown
k: string
v: Nullable<unknown>
} {
let tempObj = obj
path = path.replace(/\[(\w+)\]/g, '.$1')
path = path.replace(/^\./, '')
const keyArr = path.split('.')
let i = 0
for (i; i < keyArr.length - 1; i++) {
if (!tempObj && !strict) break
const key = keyArr[i]
if (key in tempObj) {
tempObj = tempObj[key]
} else {
if (strict) {
throw new Error('please transfer a valid prop path to form item!')
}
break
}
}
return {
o: tempObj,
k: keyArr[i],
v: tempObj?.[keyArr[i]],
}
}
/**
* Generate random number in range [0, 1000]
* Maybe replace with [uuid](https://www.npmjs.com/package/uuid)
*/
export const generateId = (): number => Math.floor(Math.random() * 10000)
// use isEqual instead
// export const valueEquals
export const escapeRegexpString = (value = ''): string =>
String(value).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
// Use native Array.find, Array.findIndex instead
// coerce truthy value to array
export const coerceTruthyValueToArray = (arr) => {
2021-01-28 22:10:45 +08:00
if (!arr && arr !== 0) {
return []
}
return Array.isArray(arr) ? arr : [arr]
}
2021-01-28 22:10:45 +08:00
export const isIE = function (): boolean {
2021-04-06 11:27:30 +08:00
return !isServer && !isNaN(Number(document.documentMode))
}
2021-01-28 22:10:45 +08:00
export const isEdge = function (): boolean {
return !isServer && navigator.userAgent.indexOf('Edge') > -1
}
2021-01-28 22:10:45 +08:00
export const isFirefox = function (): boolean {
return !isServer && !!window.navigator.userAgent.match(/firefox/i)
}
export const autoprefixer = function (style: CSSProperties): CSSProperties {
const rules = ['transform', 'transition', 'animation']
const prefixes = ['ms-', 'webkit-']
rules.forEach((rule) => {
const value = style[rule]
if (rule && value) {
prefixes.forEach((prefix) => {
style[prefix + rule] = value
})
}
})
return style
}
export const kebabCase = hyphenate
2020-09-14 10:03:33 +08:00
// reexport from lodash & vue shared
export {
2020-09-14 10:03:33 +08:00
hasOwn,
// isEmpty,
// isEqual,
isObject,
2020-09-14 10:03:33 +08:00
isArray,
isString,
capitalize,
2020-08-25 22:25:46 +08:00
camelize,
looseEqual,
extend,
}
2020-09-14 10:03:33 +08:00
export const isBool = (val: unknown) => typeof val === 'boolean'
export const isNumber = (val: unknown) => typeof val === 'number'
export const isHTMLElement = (val: unknown) => toRawType(val).startsWith('HTML')
export function rafThrottle<T extends AnyFunction<any>>(
fn: T
): AnyFunction<void> {
let locked = false
2021-01-28 22:10:45 +08:00
return function (...args: any[]) {
if (locked) return
locked = true
window.requestAnimationFrame(() => {
fn.apply(this, args)
locked = false
})
}
}
export const clearTimer = (timer: Ref<TimeoutHandle>) => {
clearTimeout(timer.value)
timer.value = null
}
/**
* Generating a random int in range (0, max - 1)
* @param max {number}
*/
export function getRandomInt(max: number) {
return Math.floor(Math.random() * Math.floor(max))
}
export function entries<T>(obj: Hash<T>): [string, T][] {
return Object.keys(obj).map((key: string) => [key, obj[key]])
}
2020-10-30 23:26:33 +08:00
export function isUndefined(val: any): val is undefined {
return val === undefined
}
export { isVNode } from 'vue'
export function useGlobalConfig() {
const vm: any = getCurrentInstance()
if ('$ELEMENT' in vm.proxy) {
return vm.proxy.$ELEMENT
}
return {}
}
2021-01-28 22:10:45 +08:00
export const arrayFindIndex = function <T = any>(
arr: Array<T>,
pred: (args: T) => boolean
): number {
return arr.findIndex(pred)
}
export const arrayFind = function <T>(
arr: Array<T>,
pred: (args: T) => boolean
): T {
return arr.find(pred)
}
2020-10-30 23:26:33 +08:00
export function isEmpty(val: unknown) {
if (
(!val && val !== 0) ||
(isArray(val) && !val.length) ||
(isObject(val) && !Object.keys(val).length)
)
return true
2020-10-30 23:26:33 +08:00
return false
}
export function arrayFlat(arr: unknown[]) {
return arr.reduce((acm: unknown[], item) => {
const val = Array.isArray(item) ? arrayFlat(item) : item
return acm.concat(val)
}, [])
}
export function deduplicate<T>(arr: T[]) {
return Array.from(new Set(arr))
2020-10-30 23:26:33 +08:00
}
/**
* Unwraps refed value
* @param ref Refed value
*/
2021-01-28 22:10:45 +08:00
export function $<T>(ref: Ref<T>) {
return ref.value
}
2021-01-28 22:10:45 +08:00
export function addUnit(value: string | number) {
if (isString(value)) {
return value
} else if (isNumber(value)) {
return value + 'px'
}
if (process.env.NODE_ENV === 'development') {
warn(SCOPE, 'binding value must be a string or number')
}
return ''
}
/**
* Enhance `lodash.isEqual` for it always return false even two functions have completely same statements.
* @param obj The value to compare
* @param other The other value to compare
* @returns Returns `true` if the values are equivalent, else `false`.
* @example
* lodash.isEqual(() => 1, () => 1) // false
* isEqualWith(() => 1, () => 1) // true
*/
export function isEqualWithFunction(obj: any, other: any) {
return isEqualWith(obj, other, (objVal, otherVal) => {
return isFunction(objVal) && isFunction(otherVal)
? `${objVal}` === `${otherVal}`
: undefined
})
}
/**
* Generate function for attach ref for the h renderer
* @param ref Ref<HTMLElement | ComponentPublicInstance>
* @returns (val: T) => void
*/
export const refAttacher = <T extends HTMLElement | ComponentPublicInstance>(
ref: Ref<T>
) => {
return (val: T) => {
ref.value = val
}
}