我是创建了一个类,将方法全部放于类中,小伙伴们若是有更优的写法或者逻辑,欢迎留言讨论交流!
class Utils {
Function() {}
......
}
export default new Utils()
转树之后用到了第二个删除空children的方法
/**
* tree-树形数据转换,转换为树结构
* @param {*} data
* @param {*} id
* @param {*} pid
*/
treeDataTranslate(data: Array<any> = [], id = 'id', pid = 'parentId', children = 'children') {
if (!data || data.length === 0) return []
let res: any[] = []
let temp: any = {}
for (let i = 0; i < data.length; i++) {
temp[data[i][id]] = data[i]
temp[data[i][id]][children] = []
temp[data[i][id]]['_level'] = null
}
for (let k = 0; k < data.length; k++) {
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
if (!temp[data[k][pid]][children]) {
temp[data[k][pid]][children] = []
}
if (!temp[data[k][pid]]['_level']) {
temp[data[k][pid]]['_level'] = 1
}
data[k]['_level'] = temp[data[k][pid]]._level + 1
temp[data[k][pid]][children].push(data[k])
} else {
res.push(data[k])
}
}
return this.treedeleteChild(res, children)
}
// tree-删除树数据子节点为空的字段
treedeleteChild(arr: any, children = 'children') {
if (!arr) return null
// 判断是否是对象
if (Object.prototype.toString.call(arr) === '[object Object]') {
arr = [arr]
}
return arr.map((item: any) => {
if (item[children]?.length > 0) {
this.treedeleteChild(item[children])
} else {
delete item[children]
}
return item
})
}
/**
* tree-递归查找树结构的第一条无children的数据
*/
queryTreeFirst(data: any, children = 'children') {
if (!data) return null;
// 判断是否是对象
if (Object.prototype.toString.call(data) === '[object Object]') {
data = [data];
}
function findNode(list: Array<any>) {
for(let i = 0; i < list.length; i++) {
if (list[i][children]?.length > 0) {
const res = findNode(list[i][children])
if (res) {
return res
}
} else {
return list[i];
}
}
}
return findNode(data);
}
此方法经常用到,查找指定id节点数据,其中加上了查指定id节点的直属父节点,传参判断是否需要即可
递归内部没有使用map/forEach循环,这两个return无法终止循环,如果使用就必须配合try{}catch(){},也没有使用for…of,以上效率都没有for高
ts具体的interface就不细写了,毕竟本身就是个anyScript
/**
* tree-递归根据id查询节点
* @param list 数据
* @param id 指定节点
* @param idName 指定节点字段名
* @param children 子数据字段名
* @param pidName 父节点名
* @param isParNode 是否返回指定节点的父节点
*/
treeFindByid(list: any, id: string, configs?: any) {
// 配置
const config = {
idName: 'id',
children: 'children',
pidName: 'parentId',
isParNode: false,
...configs,
};
// 判断是否是对象
if (Object.prototype.toString.call(list) === '[object Object]') {
list= [list];
}
function queryNode(list: Array<any>, queryid) {
const isnode = list.find((item) => item[config.idName] === queryid);
if (isnode) {
return isnode;
} else {
for (let i = 0; i < list.length; i++) {
if (list[i][config.children]?.length > 0) {
let res = queryNode(list[i][config.children], queryid);
if (res) return res;
}
}
}
}
let res = queryNode(list, id);
// 查找父节点
if (config.isParNode && obj) {
res = queryNode(list, obj[config.pidName]);
}
return res;
}
/**
* tree-递归根据id查询节点
* @param list 数据
* @param id 指定节点
* @param idName 指定节点字段名
* @param children 子数据字段名
* @param pidName 父节点名
* @param isParNode 是否返回指定节点的父节点
*/
treeFindById (data: any, id: string, configs?: any) = {
// 配置
const config = {
idName: 'id',
children: 'children',
pidName: 'parentId',
isParNode: false,
...configs,
};
// 判断是否是对象
if (Object.prototype.toString.call(data) === '[object Object]') {
data= [data];
}
function queryNode(list: Array<any>, queryid: string) {
for (let i = 0; i < list.length; i++) {
if (list[i][config.idName] === queryid) {
return list[i];
} else {
if (list[i][config.children]?.length > 0) {
let res = queryNode(list[i][config.children], queryid);
if (res) {
return res;
}
}
}
}
}
let res = queryNode(data, id)
// 查找父节点
if (config.isParNode && res) {
res = queryNode(data, res[config.pidName]);
}
return res
}
此方法是用来给树里面所有数组排序,包括所有子节点的children列表,例如菜单的展示顺序,就需要在菜单管理配置顺序
/**
* tree-树结构数据排序方法
* @param {*} data 数据
* @param {*} property 排序字段
* @param {*} order 顺序
* @param {*} children 子数组字段名
*/
treeCompareSort(data: Array<any> = [], property: string, order = 'asc', children = 'children') {
if (!data || data.length === 0 || !property) return []
function sortTree(list: Array<any>) {
const lis = list.sort(function (a, b) {
const value1: any = a[property]
const value2: any = b[property]
// 判断是否可以是有限数值
if (isFinite(value1) && isFinite(value2)) {
return order === 'asc'
? Number(value1) > Number(value2)
? 1
: -1
: Number(value1) > Number(value2)
? -1
: 1
} else {
return order === 'asc'
? value1.localeCompare(value2)
: value2.localeCompare(value1)
}
})
for(let i = 0; i < lis.length; i++) {
if (lis[i][children]?.length > 0) {
lis[i][children] = sortTree(lis[i][children])
}
}
return lis
}
return sortTree(data)
}
/**
* tree-递归获取当前节点的所有直属父/祖节点
* @param {*数据} data ,默认[]
* @param {*当前节点id的value} id
* @param {*当前节点id的key} idname
* @param {*父节点的pid名} pid
* @param {*子数据名} children
* @param {*层级字段名} levelname
*/
treeAllLevel(data: any, id: string, confi: any = {}) {
const config = { // 配置
idname: 'id',
pid: 'parentId',
children: 'children',
levelname: '_level',
...confi
}
let obj: any = {} // 按层级顺序以对象方式储存每层节点的数据
let lists: any[] = [] // 按层级顺序以数组方式储存每层节点的数据
let indexs: number[] = [] // 每一层节点的索引
// 判断是否是对象
if (data && Object.prototype.toString.call(data) === '[object Object]') {
data = [data]
}
function forFn(arr: any[], id: string) {
arr.map((item, index) => {
if (item[config.idname] === id) {
lists.push(item)
indexs.push(index)
obj[config.levelname + item[config.levelname]] = item
if (item[config.levelname] !== 1) {
forFn(data, item[config.pid])
}
} else {
if (item[config.children]?.length > 0) {
forFn(item[config.children], id)
}
}
})
}
forFn(data, id)
indexs = indexs.reverse()
lists = lists.reverse()
return { obj, list: lists, indexs: indexs }
}
/**
* tree-根据树节点查询节点下所有id
* xpei
* @param {*} treeNode 树节点
* @param {*} id id名称
* @param {*} isCur 是否包含自身id
* @param {*} children 子集名称
* @param {*} isNode 是否返回节点数组
*/
const findChildrenIds = (treeNode: any, configs?: { id?: string; children?: string; isCur?: boolean, isNode?: boolean }) => {
const config = {
id: 'id',
children: 'children',
isCur: true,
isNode: false,
...configs
}
const result: {ids: string[], nodes: any[]} = {
ids: [],
nodes: []
}
if (!treeNode) return result
if (config.isCur) {
result.ids.push(treeNode[config.id])
result.nodes.push(treeNode)
}
;(function mapIds(node: any) {
if (node.children?.length) {
for (const item of node.children) {
result.ids.push(item[config.id])
result.nodes.push(item)
mapIds(item)
}
}
})(treeNode)
return config.isNode ? result : result.ids
}
若有更多的好方法,欢迎留言交流分享…