|
| 1 | +/** |
| 2 | + * Copyright (c) 2022 - present TinyVue Authors. |
| 3 | + * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. |
| 4 | + * |
| 5 | + * Use of this source code is governed by an MIT-style license. |
| 6 | + * |
| 7 | + * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, |
| 8 | + * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR |
| 9 | + * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. |
| 10 | + * |
| 11 | + */ |
| 12 | + |
| 13 | +import { SORT } from '../common' |
| 14 | +import { isSame } from '../type' |
| 15 | +import { getObj } from '../object' |
| 16 | + |
| 17 | +/** |
| 18 | + * 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。 TINY_NO_NEED 现在数组有 findIndex |
| 19 | + * 修复数组原生的 indexOf 方法不能判断 NaN 的问题 |
| 20 | + * |
| 21 | + * let arr1 = [1, 2, 3, 4] |
| 22 | + * let arr2 = [1, 2, NaN, 4] |
| 23 | + * indexOf(arr1, 2) // 1 |
| 24 | + * indexOf(arr2, NaN) // 2 |
| 25 | + * |
| 26 | + * @param {Array} arr 要查找的数组 |
| 27 | + * @param {Object} data 需要查找的数据 |
| 28 | + * @param {Function} [predicate] 断言函数,缺省为 isSame, 两个参数为数组的元素和查找的数据 |
| 29 | + * @returns {Number} |
| 30 | + */ |
| 31 | +export const indexOf = (arr, data, predicate = isSame) => { |
| 32 | + if (Array.isArray(arr) && typeof predicate === 'function') { |
| 33 | + for (let i = 0, len = arr.length; i < len; i++) { |
| 34 | + if (predicate(arr[i], data)) { |
| 35 | + return i |
| 36 | + } |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + return -1 |
| 41 | +} |
| 42 | + |
| 43 | +/** |
| 44 | + * 在数组里查找对象,调用自定义的断言函数。 |
| 45 | + * |
| 46 | + * let arr = [1, 2, 3, 4] |
| 47 | + * find(arr, function (value) { return value > 2 }) // 3 |
| 48 | + * |
| 49 | + * @param {Array} arr 要查找的数组 |
| 50 | + * @param {Function} predicate 断言函数 |
| 51 | + * @returns {Object} |
| 52 | + */ |
| 53 | +export const find = (arr, predicate) => { |
| 54 | + const index = indexOf(arr, undefined, predicate) |
| 55 | + return index !== -1 ? arr[index] : undefined |
| 56 | +} |
| 57 | + |
| 58 | +/** |
| 59 | + * 从数组中删除指定元素,并返回该数组。 |
| 60 | + * |
| 61 | + * let arr1 = [1, 2, 3, 4] |
| 62 | + * let arr2 = [1, 2, NaN, 4] |
| 63 | + * remove(arr1, 2, 2) // [1, 4] |
| 64 | + * remove(arr2, NaN) // [1, 2, 4] |
| 65 | + * |
| 66 | + * @param {Array} arr 源数组 |
| 67 | + * @param {Object} data 需要删除的数据 |
| 68 | + * @param {Number} count 删除元素个数,默认为 1 |
| 69 | + * @returns {Array} |
| 70 | + */ |
| 71 | +export const remove = (arr, data, count = 1) => { |
| 72 | + if (Array.isArray(arr) && arr.length) { |
| 73 | + const index = indexOf(arr, data) |
| 74 | + if (index > -1) { |
| 75 | + arr.splice(index, count) |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + return arr |
| 80 | +} |
| 81 | + |
| 82 | +/** |
| 83 | + * 对象数组自定义排序,并返回该数组。 |
| 84 | + * |
| 85 | + * sort([ {a:100}, {a:1}, {a:NaN}, {a:10} ], 'a') // [ {a:1}, {a:10}, {a:100}, {a:NaN} ] |
| 86 | + * sort([ {a:100}, {a:1}, {a:NaN}, {a:10} ], 'a','desc') // [ {a:100}, {a:10}, {a:1}, {a:NaN} ] |
| 87 | + * |
| 88 | + * @param {Array} arr 需要排序的对象数组 |
| 89 | + * @param {string} field 要排序的对象字段 |
| 90 | + * @param {String} sort 排序方向,取值为 "asc" 或 "desc" |
| 91 | + * @returns {Array} 排好序的对象数组 |
| 92 | + */ |
| 93 | +export const sort = (arr, field, sort = SORT.Asc) => { |
| 94 | + if (Array.isArray(arr) && arr.length > 1) { |
| 95 | + arr.sort((x, y) => { |
| 96 | + const compare = sort === SORT.Asc ? [1, -1] : [-1, 1] |
| 97 | + const xField = getObj(x, field) |
| 98 | + const yField = getObj(y, field) |
| 99 | + |
| 100 | + if (isNaN(xField)) { |
| 101 | + return sort === SORT.Asc ? 1 : -1 |
| 102 | + } else if (isNaN(yField)) { |
| 103 | + return -1 |
| 104 | + } |
| 105 | + |
| 106 | + return xField > yField ? compare[0] : compare[1] |
| 107 | + }) |
| 108 | + } |
| 109 | + |
| 110 | + return arr |
| 111 | +} |
| 112 | + |
| 113 | +/** |
| 114 | + * 向数组中添加不重复的数据,并返回该数组。 |
| 115 | + * |
| 116 | + * let arr = [ 1, 2, NaN, 4] |
| 117 | + * push(arr, 1) // [ 1, 2, NaN, 4] |
| 118 | + * push(arr, NaN) // [ 1, 2, NaN, 4] |
| 119 | + * push(arr, 5) // [ 1, 2, NaN, 4, 5] |
| 120 | + * |
| 121 | + * @param {Array} arr 源数组 |
| 122 | + * @param {Object} data 需要增加的数据 |
| 123 | + * @returns {Array} |
| 124 | + */ |
| 125 | +export const push = (arr, data) => { |
| 126 | + if (Array.isArray(arr) && !arr.some((value) => isSame(value, data))) { |
| 127 | + arr.push(data) |
| 128 | + } |
| 129 | + |
| 130 | + return arr |
| 131 | +} |
| 132 | + |
| 133 | +/** |
| 134 | + * 去除数组中的重复的值,并返回新数组。 |
| 135 | + * |
| 136 | + * let arr = [ 1, NaN, 2, NaN, 2, 3, 4] |
| 137 | + * unique(arr) // [ 1, NaN, 2, 3, 4] |
| 138 | + * |
| 139 | + * @param {Array} arr |
| 140 | + * @returns {Array} |
| 141 | + */ |
| 142 | +export const unique = (arr) => { |
| 143 | + if (Array.isArray(arr)) { |
| 144 | + const array = [] |
| 145 | + |
| 146 | + for (let i = 0, len = arr.length; i < len; i++) { |
| 147 | + const value = arr[i] |
| 148 | + if (indexOf(array, value) === -1) { |
| 149 | + array.push(value) |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + return array |
| 154 | + } |
| 155 | + |
| 156 | + return arr |
| 157 | +} |
| 158 | + |
| 159 | +const extend = (to, _from) => { |
| 160 | + Object.keys(_from).forEach((key) => (to[key] = _from[key])) |
| 161 | + |
| 162 | + return to |
| 163 | +} |
| 164 | + |
| 165 | +/** |
| 166 | + * 数组转对象 |
| 167 | + * |
| 168 | + * let arr = [ { key1: value1 }, { key2: value2 } ] |
| 169 | + * toObject(arr) // { key1: value1, key2: value2 } |
| 170 | + * |
| 171 | + * @param {Array} arr |
| 172 | + * @returns {Object} |
| 173 | + */ |
| 174 | +export const toObject = (arr) => { |
| 175 | + const res = {} |
| 176 | + |
| 177 | + for (let i = 0; i < arr.length; i++) { |
| 178 | + if (arr[i]) { |
| 179 | + extend(res, arr[i]) |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + return res |
| 184 | +} |
| 185 | + |
| 186 | +/** |
| 187 | + * 将 id 与 pid 构成的扁平数据转换成 children 的树状数据 |
| 188 | + * |
| 189 | + * let data = [{ id: 100, pId: 0, label: '首页'}, { id: 101, pId: 100, label: '指南'}] |
| 190 | + * transformPidToChildren(data) // [ 0: { id: 100, label: "首页", children: [ 0: { id: 101, label: "指南" } ] } ] |
| 191 | + * |
| 192 | + * @param {Array} data id 与 pid 构成的扁平数据的数组 |
| 193 | + * @param {String} [pidName] pid 的属性名,缺省为 pId |
| 194 | + * @param {String} [childrenName] children 的属性名,缺省为 children |
| 195 | + * @param {String} [idName] id 的属性名,缺省为 id |
| 196 | + * @returns {Array} |
| 197 | + */ |
| 198 | +export const transformPidToChildren = (data, pidName = 'pId', childrenName = 'children', idName = 'id') => { |
| 199 | + const result = [] |
| 200 | + |
| 201 | + Array.isArray(data) && |
| 202 | + data.forEach((item) => { |
| 203 | + if (item[pidName] === '0') { |
| 204 | + result.push(item) |
| 205 | + } else { |
| 206 | + const parent = find(data, (i) => i[idName] === item[pidName]) |
| 207 | + |
| 208 | + if (!parent) { |
| 209 | + return |
| 210 | + } |
| 211 | + |
| 212 | + if (!parent[childrenName]) { |
| 213 | + parent[childrenName] = [] |
| 214 | + } |
| 215 | + |
| 216 | + parent[childrenName].push(item) |
| 217 | + } |
| 218 | + |
| 219 | + delete item[pidName] |
| 220 | + }) |
| 221 | + |
| 222 | + return result |
| 223 | +} |
| 224 | + |
| 225 | +/** |
| 226 | + * 将pid标识的普通数组转换树结构数据 |
| 227 | + * @param {*} data |
| 228 | + * @param {*} key |
| 229 | + * @param {*} parentKey |
| 230 | + */ |
| 231 | +export const transformTreeData = (data, key = 'id', parentKey = 'pId') => { |
| 232 | + if (!Array.isArray(data)) { |
| 233 | + data = [data] |
| 234 | + } |
| 235 | + |
| 236 | + data = data.map((item) => ({ ...item })) |
| 237 | + |
| 238 | + const treeData = transformPidToChildren(data, parentKey, 'children', key) |
| 239 | + return treeData |
| 240 | +} |
0 commit comments