UNPKG

antd-multi-asl-cascader

Version:

A multiple cascader component for antd

400 lines (399 loc) 13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transTreeNodesToArray = exports.findAllLeafNode = exports.transPropsValueToValues = exports.shallowEqualArray = exports.transformValue = exports.reconcile = exports.sinkTreeState = exports.liftTreeState = exports.removeAllDescendanceValue = exports.matchAllLeafValue = exports.isParentChecked = exports.hasChildChecked = exports.flattenTree = void 0; // 平铺树结构,方便根据 value(字符串) 获取到所有的 NodeItem 节点 // 添加 parent 链接到父节点 function flattenTree(root) { const res = []; function dfs(nodes, parent = null) { if (!nodes) { return; } const newChildren = []; for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; const { children } = node; const newNode = Object.assign(Object.assign({}, node), { parent }); res.push(newNode); newChildren.push(newNode); if (children) { dfs(children, newNode); } } if (parent) { // eslint-disable-next-line no-param-reassign parent.children = newChildren; } } dfs(root); return res; } exports.flattenTree = flattenTree; // 是否有子节点(包括自己)被选中 function hasChildChecked(item, curValue) { function dfs(node) { if (!node) { return false; } const { children } = node; if (curValue.includes(node)) { return true; } if (!children) { return false; } return children.some((child) => dfs(child)); } return dfs(item); } exports.hasChildChecked = hasChildChecked; /** * 判断两个节点是不是彻底相等 * @param node 当前节点 * @param comparedNode 被比较的节点 */ function isSameNode(node, comparedNode) { // 终止条件 if (node == null && comparedNode == null) { return true; } if ((node === null || node === void 0 ? void 0 : node.value) !== (comparedNode === null || comparedNode === void 0 ? void 0 : comparedNode.value)) { return false; } return isSameNode(node === null || node === void 0 ? void 0 : node.parent, comparedNode === null || comparedNode === void 0 ? void 0 : comparedNode.parent); } /** * 判断当前的 nodeList 里是否有 node * @param nodeList node列表 * @param node 当前节点 * @returns */ function isHasSameNode(nodeList, node) { let res = false; nodeList.forEach(eachNode => { if (isSameNode(eachNode, node)) { res = true; } }); return res; } // 是否有父节点(包括自己)被选中 /** * * @param item 被更改的节点 * @param value 之前全部选择的值 * @returns */ function isParentChecked(item, value) { let tmp = item; while (tmp) { const isExist = value.find(eachValue => isSameNode(tmp, eachValue)); if (isExist) { return true; } tmp = tmp.parent; } return false; } exports.isParentChecked = isParentChecked; function matchAllLeafValue(value, roots) { const res = []; function dfs(nodes, needed) { if (!nodes) { return; } nodes.forEach((node) => { const { children } = node; if (needed || isHasSameNode(value, node)) { if (!children) { // 叶子节点 res.push(node); } else { dfs(children, true); } } else { dfs(children, needed); } }); } dfs(roots, false); return Array.from(new Set(res)); } exports.matchAllLeafValue = matchAllLeafValue; /** * 获取 root 下全部的子元素(不包含root本身),再对value进行一层过滤,过滤掉root下的子元素 * @param root 当前选中节点 的最顶层节点 * @param value 已经选中的值 * @returns 更改后的value */ function removeAllDescendanceValue(root, value) { const allChildrenValue = []; function dfs(node) { if (node.children) { node.children.forEach((item) => { allChildrenValue.push(item); dfs(item); }); } } dfs(root); return value.filter((val) => !isHasSameNode(allChildrenValue, val)); } exports.removeAllDescendanceValue = removeAllDescendanceValue; // 状态提升 function liftTreeState( // 被更改的节点 item, // 之前全部选择的值 curVal) { var _a; // 加入当前节点 value const nextValue = curVal.concat(item); let last = item; // eslint-disable-next-line no-constant-condition while (true) { // 如果父节点的所有子节点都已经 checked, 添加该节点 value,继续尝试提升 if (last && ((_a = last === null || last === void 0 ? void 0 : last.parent) === null || _a === void 0 ? void 0 : _a.children.every((child) => isHasSameNode(nextValue, child)))) { nextValue.push(last.parent); last = last.parent; } else { break; } } // 找到被更改的节点item受影响的顶级父元素,删除nextValue中 属于父元素的子元素 return removeAllDescendanceValue(last, nextValue); } exports.liftTreeState = liftTreeState; // 找到 受 被更改的节点 影响的父级节点 function getCheckedParent(node, parentValues, value) { if (!node) { return null; } parentValues.push(node); if (isHasSameNode(value, node)) { return node; } return getCheckedParent(node.parent, parentValues, value); } // 状态下沉 /** * 如果它的父元素被选中,则删除父元素,把父元素下选择的子元素都推入value * @param root 被更改的节点 * @param value 之前全部选择的值 * @returns */ function sinkTreeState(root, value) { // value 这条路径下的全部节点(包含自己) const parentValues = []; // checkedParent下的全部叶子节点(不包含自己) const subTreeValues = []; // 找到 受 被更改的节点 影响的父级节点 const checkedParent = getCheckedParent(root, parentValues, value); // 如果没有,则根本不需要管他 if (!checkedParent) { return value; } function dfs(node) { if (!node.children || node.value === root.value) { return; } node.children.forEach((item) => { if (item.value !== root.value) { if (parentValues.includes(item)) { dfs(item); } else { subTreeValues.push(item); } } }); } dfs(checkedParent); // 替换 checkedParent 下子树的值 const nextValue = removeAllDescendanceValue(checkedParent, value).filter((item) => item !== checkedParent); return Array.from(new Set(nextValue.concat(subTreeValues))); } exports.sinkTreeState = sinkTreeState; // checked, unchecked 时重新计算 // 如果父节点已经选中了,返回之前全部选择的值(兼容父元素后) /** * 把变动的节点(不管是选中还是没选中),从value里新增或删除时,兼容它的父节点与子节点 * @param item 变动的节点 * @param checked 变动的节点到底是选中还是未选中状态 * @param value 之前全部选择的值 * @returns TreeNode[] */ function reconcile(item, checked, value) { if (checked) { // 如果已经有父节点被 checked, 再进行 checked 没有意义,直接忽略 // 主要是用在避免初始化时传入的 value 结构不合理 if (isParentChecked(item, value)) { return value; } return liftTreeState(item, value); } return sinkTreeState(item, value); } exports.reconcile = reconcile; // // 按树的 dfs 前序排 // export function sortByTree(value: TreeNode[], flattenData: TreeNode[]) { // // 按照树结构前顺排序 // const map = flattenData.reduce( // (cur: Record<string, number>, node: TreeNode, index: number) => { // cur[node.value] = index // return cur // }, // {} // ) // return value.sort((a, b) => map[a.value] - map[b.value] || 0) // } // 过滤非法数据,排序 function transformValue(value, flattenData) { let nextValue = []; for (let i = 0; i < value.length; i++) { const node = flattenData.find((item) => isSameNode(item, value[i])); if (node) { nextValue = reconcile(node, true, nextValue); } else { nextValue.push(value[i]); } } // return sortByTree(nextValue, flattenData) return nextValue; } exports.transformValue = transformValue; function shallowEqualArray(arrA, arrB) { if (arrA === arrB) { return true; } if (!arrA || !arrB) { return false; } var len = arrA.length; if (arrB.length !== len) { return false; } for (var i = 0; i < len; i++) { if (arrA[i] !== arrB[i]) { return false; } } return true; } exports.shallowEqualArray = shallowEqualArray; // // 通过 value 查找树节点 // export function findNodeByValue( // value: string, // tree: TreeNode[] // ): TreeNode | undefined { // function findParent(nodes: TreeNode[]): TreeNode | undefined { // if (!nodes) { // return undefined // } // for (let i = 0; i < nodes.length; i++) { // const node = nodes[i] // if (value === node.value) { // return node // } // if (node.children) { // const foundInChildren = findParent(node.children) // if (foundInChildren) { // return foundInChildren // } // } // } // } // return findParent(tree) // } /** * 在 allData 里查找出 propsValue 里全部的节点 * @param propsValues 用户输入的value * @param allData 全部的节点 * @returns */ function transPropsValueToValues(propsValues, allData) { let res = []; propsValues.forEach(eachNodeValues => { let nodeArr = []; let curLevelNodes = allData; for (let i = 0; i < eachNodeValues.length; i++) { let curNode = curLevelNodes === null || curLevelNodes === void 0 ? void 0 : curLevelNodes.find(node => node.value === eachNodeValues[i]); curLevelNodes = (curNode === null || curNode === void 0 ? void 0 : curNode.children) || []; if (curNode) { nodeArr.push(curNode); } else { nodeArr = []; break; } } for (let i = nodeArr.length - 1; i > 0; i--) { nodeArr[i].parent = nodeArr[i - 1]; } if (nodeArr.length) { res = reconcile(nodeArr[nodeArr.length - 1], true, res); } }); return res; } exports.transPropsValueToValues = transPropsValueToValues; /** * 把 TreeNode 类型的树型节点转换成数组对象(返回给onchange的第二个参数) * @param leafNode * @returns */ function transLeafToPathArr(leafNode) { let res = []; let curNode = leafNode; while (curNode) { res.unshift(curNode); curNode = curNode.parent; } return res; } /** * 把 selectedNode 里的全部叶子节点或自身推送到 selectedNodeLeafArr 里去 * @param selectedNode 被推入的节点 * @param selectedNodeLeafArr 被推入的数组 * @returns */ function dfsSelectedNode(selectedNode, selectedNodeLeafArr) { // 设置终止条件 if (!selectedNode.children) { selectedNodeLeafArr.push(selectedNode); return; } selectedNode.children.forEach(childNode => dfsSelectedNode(childNode, selectedNodeLeafArr)); } // 获取 selectedNodes 下所有节点到叶子节点的全部路径 function findAllLeafNode(selectedNodes) { const res = []; selectedNodes.forEach(selectedNode => { // 如果 selectedNode 是叶子节点 if (!selectedNode.children) { res.push(transLeafToPathArr(selectedNode)); return; } // 如果 selectedNode 不是叶子节点,则要获取它全部的叶子节点 const selectedNodeLeafArr = []; dfsSelectedNode(selectedNode, selectedNodeLeafArr); selectedNodeLeafArr.forEach((leafNode) => { res.push(transLeafToPathArr(leafNode)); }); }); return res; } exports.findAllLeafNode = findAllLeafNode; // 把多维的叶子节点数组,转换成字符串类型的数组 function transTreeNodesToArray(treeNodes) { return treeNodes.map(treeNode => { const values = []; treeNode.forEach(eachLevelNode => values.push(eachLevelNode.value)); return values; }); } exports.transTreeNodesToArray = transTreeNodesToArray;