javascript自己的工具函数

使用 export 语法将工具函数暴露出去

/**
 * @function 生成UUID
 * @export 导出为工具函数
 * @return {String} 返回值为生成的UUID
 */
export const generateUUID = () => {
  let date = new Date().getTime();
  let uuid = "xxxx_xxxx_xxxx_yxxx".replace(/[xy]/g, function (char) {
    let random = (date + Math.random() * 16) % 16 | 0;
    date = Math.floor(date / 16);
    return (char == "x" ? random : (random & 0x7) | 0x8).toString(16);
  });
  return uuid;
};

/**
 * @function 深拷贝对象
 * @export 导出为工具函数
 * @param {Object|Array} 入参为被拷贝对象或数组
 * @return {Object|Array} 返回值为拷贝出的对象或数组
 */
export const deepCopyObject = (obj) => {
  let newObj;
  Array.isArray(obj) ? (newObj = []) : (newObj = {});
  const keyArray = Object.keys(obj);
  keyArray.forEach((key) => {
    if (typeof obj[key] == "object" && obj[key] != null) {
      newObj[key] = deepCopyObject(obj[key]);
    } else {
      newObj[key] = obj[key];
    }
  });
  return newObj;
};

/**
 * @function 根据id和parentId生成树
 * @export 导出为工具函数
 * @param {Object} 所有参数都在对象中
 * @param {Array} [data=[]] 生成树的原始一维数组,默认为[]
 * @param {String|Number} [rootId = 0] 根节点id,默认为0
 * @param {String} [id="id"] id字段名,默认为"id"
 * @param {String} [parentId="parentId"] parentId字段名,默认为"parentId"
 * @param {String} [children="children"] children字段名,默认为"children"
 * @return {Array} 返回生成树的数组
 */
export const createTree = ({ data = [], rootId = 0, id = "id", parentId = "parentId", children = "children" } = {}) => {
  // 过滤遍历树原始数组,当前遍历项为父节点,返回根节点数组
  return data.filter((parent) => {
    parent.expand = true;
    // 嵌套过滤遍历树原始数组,当前遍历项为子节点,返回当前父节点的所有子节点
    let branchArr = data.filter((child) => {
      return parent[id] == child[parentId];
    });
    if (branchArr.length > 0) {
      // 若存在子节点,则给父节点添加一个children属性,并将branchArr赋值给父节点
      parent[children] = branchArr;
    }
    return parent[parentId] == rootId; //返回根节点数组
  });
};
/**
 * 通过id与parentId的一维数组生成树(Typescript)
 * 该方法相较上面的filter递归方式执行效率更高,时间复杂度由O(n2)降低为O(n)
 * @param 配置对象 data为原始数据;rootId为根节点对应的id值;idAttr为id字段名,默认为id;parentAttr为父id字段名,默认为parentId;childrenAttr为子节点字段名,默认为children
 * @returns 树数组
 */
export const createTree = ({
  data = [],
  rootId = 0,
  idAttr = "id",
  parentAttr = "parentId",
  childrenAttr = "children",
}: {
  data: { [key: string]: any }[],
  rootId?: number,
  idAttr?: string,
  parentAttr?: string,
  childrenAttr?: string,
}) => {
  // 生成用于查找父节点的map
  const map = data.reduce((map, item, index) => {
    map[item[idAttr]] = index;
    item[childrenAttr] = [];
    return map;
  }, {});
  // 将每个元素挂载到对应的父节点
  return data.reduce((tree, item, index, arr) => {
    // 若当前节点的父节点为根节点,则放入最终的树数组
    if (item[parentAttr] === rootId) tree.push(item);
    // 否则将当前节点挂载到相应的父节点上
    else {
      // 判断父节点是否存在于map中,存在则挂载,否则报错
      if (map[item[parentAttr]] !== undefined) arr[map[item[parentAttr]]][childrenAttr].push(item);
      else console.error(`Id ${item[idAttr]} No Parent Found`);
    }
    return tree;
  }, []);
};

/**
 * @function iview手风琴树(每次只展开一个树节点)
 * @export 导出为工具函数
 * @param {Object} 入参1:当前节点对象
 * @param {Array} 入参2:树的数组数据
 */
export const accordionTree = (currentNode, treeData) => {
  /**
   * @function 查找当前节点父节点
   * @param {Array} 入参1:树的数组数据
   * @param {Object} 入参2: 当前节点对象
   * @return {Object} 返回值为当前节点的父节点对象
   */
  function findParent(treeData, currentNode) {
    // 声明最终父节点
    let finalParentNode = null;
    /**
     * @function 查找当前节点父节点的内部递归函数
     * @param {Array} 入参1:树的数组数据
     * @param {Object} 入参2:当前点击节点对象
     * @param {Object} 入参3:此时遍历节点的父节点
     */
    function findParentInner(treeData, currentNode, parentNode) {
      // 内部查找函数,若当前节点nodeKey与遍历节点nodeKey相同时,则此时的parentNode为要找的最终父节点,否则判断遍历节点是否存在子节点,若存在则递归执行函数,若不存在则什么都不做
      treeData.forEach((item) =>
        item.nodeKey === currentNode.nodeKey
          ? (() => {
              finalParentNode = parentNode;
            })()
          : (() => {
              item.children ? findParentInner(item.children, currentNode, item) : "";
            })()
      );
    }
    // 执行内部函数
    findParentInner(treeData, currentNode, finalParentNode);
    return finalParentNode;
  }
  /**
   * @function 折叠树其它节点
   * @param {Array} 入参1:树的数组数据
   * @param {Object} 入参2:当前点击节点对象
   */
  function collapseTree(treeData, currentNode) {
    treeData.forEach((item) => {
      // 若遍历节点为折叠则什么都不做,若为展开则判断遍历节点与当前节点nodeKey是否相同,若相同则什么都不做,否则设为折叠
      item.expand
        ? (() => {
            item.nodeKey === currentNode.nodeKey ? "" : (item.expand = false);
          })()
        : (() => {})();
      // 若遍历节点存在子节点则递归此函数,否则什么都不做
      item.children ? collapseTree(item.children, currentNode) : "";
    });
  }
  // 找到当前点击节点的父节点
  let parentNode = findParent(treeData, currentNode);
  // 折叠树,若父节点为null,则为根节点,传入所有树数据(根节点);若不为null,则传入父节点的子节点
  parentNode === null ? collapseTree(treeData, currentNode) : collapseTree(parentNode.children, currentNode);
};

参考资料 生成树方法 createTree