* Copyright (c) 2022 - present TinyVue Authors.
* Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { SORT } from '../common'
import { isSame } from '../type'
import { getObj } from '../object'
* 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。 TINY_NO_NEED 现在数组有 findIndex
* 修复数组原生的 indexOf 方法不能判断 NaN 的问题
*
* let arr1 = [1, 2, 3, 4]
* let arr2 = [1, 2, NaN, 4]
* indexOf(arr1, 2) // 1
* indexOf(arr2, NaN) // 2
*
* @param {Array<T>} arr 要查找的数组
* @param {T} data 需要查找的数据
* @param {Function} [predicate] 断言函数,缺省为 isSame, 两个参数为数组的元素和查找的数据
* @returns {number} 元素在数组中的索引,如果不存在则返回-1
*/
export const indexOf = <T>(arr: T[], data: T, predicate: (item: T, target: T) => boolean = isSame): number => {
if (Array.isArray(arr) && typeof predicate === 'function') {
for (let i = 0, len = arr.length; i < len; i++) {
if (predicate(arr[i], data)) {
return i
}
}
}
return -1
}
* 在数组里查找对象,调用自定义的断言函数。
*
* let arr = [1, 2, 3, 4]
* find(arr, function (value) { return value > 2 }) // 3
*
* @param {Array<T>} arr 要查找的数组
* @param {Function} predicate 断言函数
* @returns {T | undefined} 找到的元素,如果没有找到则返回undefined
*/
export const find = <T>(arr: T[], predicate: (item: T, index: number) => boolean): T | undefined => {
const index = indexOf(arr, undefined as any, predicate as any)
return index !== -1 ? arr[index] : undefined
}
* 从数组中删除指定元素,并返回该数组。
*
* let arr1 = [1, 2, 3, 4]
* let arr2 = [1, 2, NaN, 4]
* remove(arr1, 2, 2) // [1, 4]
* remove(arr2, NaN) // [1, 2, 4]
*
* @param {Array<T>} arr 源数组
* @param {T} data 需要删除的数据
* @param {number} count 删除元素个数,默认为 1
* @returns {Array<T>} 处理后的数组
*/
export const remove = <T>(arr: T[], data: T, count = 1): T[] => {
if (Array.isArray(arr) && arr.length) {
const index = indexOf(arr, data)
if (index > -1) {
arr.splice(index, count)
}
}
return arr
}
* 对象数组自定义排序,并返回该数组。
*
* sort([ {a:100}, {a:1}, {a:NaN}, {a:10} ], 'a') // [ {a:1}, {a:10}, {a:100}, {a:NaN} ]
* sort([ {a:100}, {a:1}, {a:NaN}, {a:10} ], 'a','desc') // [ {a:100}, {a:10}, {a:1}, {a:NaN} ]
*
* @param {Array<T>} arr 需要排序的对象数组
* @param {string} field 要排序的对象字段
* @param {string} sort 排序方向,取值为 "asc" 或 "desc"
* @returns {Array<T>} 排好序的对象数组
*/
export const sort = <T extends Record<string, any>>(arr: T[], field: string, sort: string = SORT.Asc): T[] => {
if (Array.isArray(arr) && arr.length > 1) {
arr.sort((x, y) => {
const compare = sort === SORT.Asc ? [1, -1] : [-1, 1]
const xField = getObj(x, field)
const yField = getObj(y, field)
if (isNaN(xField)) {
return sort === SORT.Asc ? 1 : -1
} else if (isNaN(yField)) {
return -1
}
return xField > yField ? compare[0] : compare[1]
})
}
return arr
}
* 向数组中添加不重复的数据,并返回该数组。
*
* let arr = [ 1, 2, NaN, 4]
* push(arr, 1) // [ 1, 2, NaN, 4]
* push(arr, NaN) // [ 1, 2, NaN, 4]
* push(arr, 5) // [ 1, 2, NaN, 4, 5]
*
* @param {Array<T>} arr 源数组
* @param {T} data 需要增加的数据
* @returns {Array<T>} 处理后的数组
*/
export const push = <T>(arr: T[], data: T): T[] => {
if (Array.isArray(arr) && !arr.some((value) => isSame(value, data))) {
arr.push(data)
}
return arr
}
* 去除数组中的重复的值,并返回新数组。
*
* let arr = [ 1, NaN, 2, NaN, 2, 3, 4]
* unique(arr) // [ 1, NaN, 2, 3, 4]
*
* @param {Array<T>} arr 源数组
* @returns {Array<T>} 去重后的新数组
*/
export const unique = <T>(arr: T[]): T[] => {
if (Array.isArray(arr)) {
const array: T[] = []
for (let i = 0, len = arr.length; i < len; i++) {
const value = arr[i]
if (indexOf(array, value) === -1) {
array.push(value)
}
}
return array
}
return arr
}
* 将一个对象的属性复制到另一个对象
*
* @param {Record<string, any>} to 目标对象
* @param {Record<string, any>} _from 源对象
* @returns {Record<string, any>} 目标对象
*/
const extend = (to: Record<string, any>, _from: Record<string, any>): Record<string, any> => {
Object.keys(_from).forEach((key) => (to[key] = _from[key]))
return to
}
* 数组转对象
*
* let arr = [ { key1: value1 }, { key2: value2 } ]
* toObject(arr) // { key1: value1, key2: value2 }
*
* @param {Array<Record<string, any>>} arr 包含对象的数组
* @returns {Record<string, any>} 合并后的对象
*/
export const toObject = (arr: Record<string, any>[]): Record<string, any> => {
const res: Record<string, any> = {}
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
}
* 将 id 与 pid 构成的扁平数据转换成 children 的树状数据
*
* let data = [{ id: 100, pId: 0, label: '首页'}, { id: 101, pId: 100, label: '指南'}]
* transformPidToChildren(data) // [ 0: { id: 100, label: "首页", children: [ 0: { id: 101, label: "指南" } ] } ]
*
* @param {Array<Record<string, any>>} data id 与 pid 构成的扁平数据的数组
* @param {string} [pidName] pid 的属性名,缺省为 pId
* @param {string} [childrenName] children 的属性名,缺省为 children
* @param {string} [idName] id 的属性名,缺省为 id
* @returns {Array<Record<string, any>>} 树状结构数据
*/
export const transformPidToChildren = (
data: Record<string, any>[],
pidName = 'pId',
childrenName = 'children',
idName = 'id'
): Record<string, any>[] => {
const result: Record<string, any>[] = []
Array.isArray(data) &&
data.forEach((item) => {
if (!item[pidName] || item[pidName] === '0') {
result.push(item)
} else {
const parent = find(data, (i) => i[idName] === item[pidName])
if (!parent) {
return
}
if (!parent[childrenName]) {
parent[childrenName] = []
}
parent[childrenName].push(item)
}
delete item[pidName]
})
return result
}
* 将pid标识的普通数组转换树结构数据
*
* @param {Record<string, any> | Record<string, any>[]} data 需要转换的数据
* @param {string} key id的属性名,默认为'id'
* @param {string} parentKey 父id的属性名,默认为'pId'
* @returns {Record<string, any>[]} 树状结构数据
*/
export const transformTreeData = (
data: Record<string, any> | Record<string, any>[],
key = 'id',
parentKey = 'pId'
): Record<string, any>[] => {
let dataArray: Record<string, any>[]
if (!Array.isArray(data)) {
dataArray = [data]
} else {
dataArray = data
}
dataArray = dataArray.map((item) => ({ ...item }))
const treeData = transformPidToChildren(dataArray, parentKey, 'children', key)
return treeData
}