layui自带的tree组件,默认情况下,父子节点是关联的。但是某些业务场景下,我们需要取消父子关联,或者只取消子关联父。我的业务需求要解决的问题包括如下几个方面:
1. 取消子对父的关联,即当选择父节点下的子节点,或取消勾选子节点,均不会对父节点有任何影响.
首先找到layui文件夹modules里面的tree.js,把setCheckbox方法里面的内容改成如下内容:
上面改造的作用是取消子级对父级的关联,无论子集正反选,均不对父级产生影响。
2.勾选项默认展开
- 我的业务需求是在弹出层中展示用户的管辖公司,勾选后可以获取一个或多个公司的数据.
- 当打开弹窗时,被勾选中的项及其父项是需要展开的,通过官方文档可以知道,与节点展开有关的属性为:spread,当其为true时,对应数据项展开(这里注意一点,当被勾选的是最底层,即没有子级,给其加上spread:true,节点也不会展开,需要给其父元素加spread:true)
- 可以通过递归来获取树形数据,获取每一项的id,同时再用被勾选的id去对比,即可判断出哪些项被勾选,从而加上spread。
- 这里我在tree.js中自定义了一个获取用户勾选项的id的方法,如下图:
- 在页面的js中定义一个数组,用于存放被勾选的id,再调用getCheckedId方法存入id,最后调用封装好的函数进行对比添加spread:true,具体如下:
```var arr = [] //存储选中的id
// 辅助函数:向上遍历树结构并给遇到的每个父节点添加spread: true
function setSpreadUpward(company) {
while (company) {
company.spread = true; // 设置当前节点的spread为true
company = company.parent; // 向上移动到父节点
}
}
// 递归函数,用于遍历树形结构中的子公司
function traverseTree(companies, arr, parent = null) {
companies.forEach(function (company) {
// 设置父节点引用(仅第一次遍历时需要)
if (parent) {
company.parent = parent;
}
// 检查当前节点的orgNo是否在arr数组中
if (arr.includes(company.myId)) {
setSpreadUpward(company); // 如果在,则向上设置spread: true
} else if (company.spread) {
delete company.spread; // 如果不在但之前设置了spread: true,则移除
}
// 递归遍历子公司(如果存在)
if (company.treeCompanies) {
traverseTree(company.treeCompanies, arr, company);
}
});
}
layui.use('tree', function () {
tree = layui.tree;
tree.render({ // 初始化tree组件
elem: "#customContent",
data: companyLists,
showCheckbox: true, // 是否显示复选框
contact: false,
id: 'test',
isJump: false,
customName: {
id: 'myId',
title: 'myName',
children: 'treeCompanies'
},
oncheck: function (obj) {
arr = tree.getCheckedId('test'); //获取点击的节点
traverseTree(companyLists, arr);
}
})
})
var customLayerIndex = layer.open({
type: 1,
title: false,
shadeClose: false,
closeBtn: false,
anim: 'left',
area: ['90%', '100%'],
offset: 'lt', // 弹出层的位置,lt 表示 left top,即左上角对齐
shift: 0, // 弹出层的坐标偏移量,可以微调位置
content: $("#customLayerContent"),
success: function (layero, index) {
var shade = $('.layui-layer-shade');
shade.on('click', function (e) {
e.stopPropagation(); // 阻止事件冒泡
return false
});
$(layero).css('left', '0px'); // 确保弹出层靠左
$('#closeDialog', '#customLayerContent', layero).on('click', function () {
layer.close(customLayerIndex); // 点击关闭按钮时关闭弹窗
$('#checkBtn', layero).off('click');// 清理checkBtn的点击事件处理器
});
}
})
3. 打开弹窗,树状图保持上一次的选中状态
- 这里需要注意一点,由于我们只取消了子勾选父,没有取消父勾选子,所以当勾选了父级,再把子集全部取消勾选后,当再次打开弹窗,会发现原本取消的子级又被勾选上了。要解决这个问题,可以再渲染完tree组件后,调用之前在tree.js中定义的setChecked方法,以此来设置勾选状态。