Vue树数据常用方法

我是创建了一个类,将方法全部放于类中,小伙伴们若是有更优的写法或者逻辑,欢迎留言讨论交流!

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
    })
  }
三、递归查找树结构的第一条无children的数据
  /**
  * 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节点数据,其中加上了查指定id节点的直属父节点,传参判断是否需要即可
递归内部没有使用map/forEach循环,这两个return无法终止循环,如果使用就必须配合try{}catch(){},也没有使用for…of,以上效率都没有for高
ts具体的interface就不细写了,毕竟本身就是个anyScript

  1. 方法一,一层一层查
  /**
 * 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;
  }
  1. 方法二,一个节点往下查
  /**
 * 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 }
  }
七、递归根据树节点查询节点下所有id
/**
 * 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
}

若有更多的好方法,欢迎留言交流分享…

你可能感兴趣的:(vue常用工具,vue.js,javascript,前端)