理想是火,点燃熄灭的灯。
先看效果图:
父节点联动的规则如下:
第一种情况:全部子节点勾选,则父节点也勾选 即checked = true
第二种情况:子节点全部取消勾选,则父节点取消勾选 即checked = false
第三种情况:部分子节点勾选,则父节点也勾选 即checked = true
实现思路:
在之前的逻辑上 - 即点击某个节点 其子节点也全部自动勾选,
得到的一组数据之后,(不在之前的逻辑上直接设置关联的父节点,因为子节点是从上往下递归,而父节点需要至下而上的寻找)
单独写一个关联父节点的方法:
1.首先根据所勾选的节点,查找到它的全部父节点(可能父节点还有父节点所以需要递归)
两个参数,一个所勾选的节点(多个,单个),一个完整的tree数据
// 根据树子节点(单个,多个)寻找所有父节点 export const findParentNodes = (selected, tree) => { let spreadTreeData = setSpreadTreeData(tree, false, []); let parsentNodes = []; let deep = (parentId, parsentNodes) => { for (let tree of spreadTreeData) { if (tree.id == parentId) { parsentNodes.push(tree); if (tree.parentId) { deep(tree.parentId, parsentNodes); } } } return parsentNodes; }; // autotemplate 组件传递的seleted是个array需要处理 if (Array.isArray(selected)) { for (let selectedItem of selected) { parsentNodes = deep(selectedItem.parentId, parsentNodes); } } else { parsentNodes = deep(selected.parentId, parsentNodes); } return parsentNodes; };
还需要一个平铺tree数据的方法:setSpreadTreeData
// 平铺tree // 此函数的作用:拿到树结构后 进行树结构的渲染 同时需要把已经checked的数据 平铺到一层 // 主要是因为Autocomplete组件需要进行渲染 是个只有一层的array // jugdeCheck 这个字段如果平铺不需要判断是否checked 就不需要传递 export const setSpreadTreeData = (tree, jugdeCheck, data = []) => { for (let i = 0; i < tree.length; i++) { let item = tree[i]; if (jugdeCheck) { if (item.checked) { data.push(item); } } else { data.push(item); } item.children && setSpreadTreeData(item.children, jugdeCheck, data); } return data; };
2.得到所勾选的子节点的全部父节点之后,再单独写一个方法,传递之前已经处理勾选逻辑的数据,
进行向上遍历。
// 根据所勾选的子节点 关联其父节点 export const cascaderParsent = (parsents, checked, tree) => { for (let i = 0; i < tree.length; i++) { let item = tree[i]; for (let parsent of parsents) { // console.log('parsent::', parsent); if (parsent.id === item.id) { let { checkedNodes, activeNodeChildren } = setSpreadTreeDataCascader( parsent.children || [] ); // 第一种情况:全部子节点勾选,则父节点也勾选 即checked = true // 第二种情况:子节点全部取消勾选,则父节点取消勾选 即checked = false // 第三种情况:部分子节点勾选,则父节点也勾选 即checked = true // console.log('checkedNodes::', checkedNodes); // console.log('activeNodeChildren::', activeNodeChildren); if (checkedNodes.length === activeNodeChildren.length) { item.checked = true; } else if (checkedNodes.length === 0 && activeNodeChildren.length > 0) { item.checked = false; } else { item.checked = true; } } } if (item.children) { // 继续往子集找 cascaderParsent(parsents, checked, item.children); } } return tree; };
这里判断父节点是是勾选或者是不勾选的逻辑是根据:
1.父节点全部的子节点
2.父节点已激活的子节点
判断逻辑如下:
第一种情况:全部子节点勾选,则父节点也勾选 即checked = true
第二种情况:子节点全部取消勾选,则父节点取消勾选 即checked = false
第三种情况:部分子节点勾选,则父节点也勾选 即checked = true
这里还有一个平铺的方法:setSpreadTreeDataCascader
也可以使用之前的setSpreadTreeData ,但是需要递归两次
像这样:
// 全部节点 let activeNodeChildrenCount = setSpreadTreeData(node.children); //获取当前父节点当前所有激活的子节点 let checkedNodes = setSpreadTreeData(node.children, true);
但是效率很低,理想的状态是一次递归就生成两种所需数据:
改造一下:
// tree联动平铺专用 export const setSpreadTreeDataCascader = ( tree, checkedNodes = [], //已勾选的节点 activeNodeChildren = [] //全部节点 - 包含已勾选和未勾选 ) => { for (let i = 0; i < tree.length; i++) { let item = tree[i]; if (item.checked) { checkedNodes.push(item); } activeNodeChildren.push(item); item.children && setSpreadTreeDataCascader( item.children, checkedNodes, activeNodeChildren ); } return { checkedNodes, activeNodeChildren }; };
然后取值就可以这样做了:
let { checkedNodes, activeNodeChildren } = setSpreadTreeDataCascader( node.children || [] );
然后就是material chekbox的ui
横杠的ui其实就是checkbox的indeterminate属性
判断就行即可(代码为递归的一部分,前置还有treeItem的自定义label):
判断ui的逻辑为:
有子集的情况下:
第一种情况:全部子节点勾选,则父节点也是勾选的样式1 即indeterminate = false
第二种情况:子节点全部取消勾选,则父节点是勾选的样式1 即即indeterminate = false
第三种情况:部分子节点勾选,则父节点是勾选的样式2 即indeterminate = true
// 判断chekbox样式 - 优化方案 let jugdeIndetermainte = (node) => { let { checkedNodes, activeNodeChildren } = setSpreadTreeDataCascader( node.children || [] ); // 有子集的情况下: // 第一种情况:全部子节点勾选,则父节点也是勾选的样式1 即indeterminate = false // 第二种情况:子节点全部取消勾选,则父节点是勾选的样式1 即即indeterminate = false // 第三种情况:部分子节点勾选,则父节点是勾选的样式2 即indeterminate = true // console.log('checkedNodes::', checkedNodes.length); // console.log('activeNodeChildren::', activeNodeChildren.length); if ( checkedNodes.length === activeNodeChildren.length || (checkedNodes.length === 0 && activeNodeChildren.length > 0) ) { return false; } else { return true; } }; <Checkbox indeterminate={jugdeIndetermainte(node)} checked={node.checked} color="primary" onChange={(e) => { //balabala }} />
然后没什么了
有疑问可以留言
拜拜 各位同学!
作者: Bill 本文地址: http://biaoblog.cn/info?id=1670913555557
版权声明: 本文为原创文章,版权归 biaoblog 个人博客 所有,欢迎分享本文,转载请保留出处,谢谢!