Angular Materials Tree:实现部分节点互斥单选、部分节点多选
实现Angular Material树组件的混合单选/多选逻辑
针对你的需求,只需在原有全多选树的基础上,通过标记单选组节点和重写选中事件逻辑就能实现部分节点单选、其余多选的效果,具体步骤如下:
1. 扩展节点数据结构,标记单选组
首先给扁平节点(FlatNode)添加标识字段,用来区分哪些节点属于单选组:
// 定义扁平节点接口,新增radioGroup字段标记所属单选组 interface TodoItemFlatNode { expandable: boolean; name: string; level: number; radioGroup?: string; // 可选字段,非空则表示该节点属于对应单选组 }
在构建扁平节点的转换方法中,判断节点是否属于Quantity:的子节点,给它们打上单选组标记:
private _transformer = (node: TodoItemNode, level: number) => { return { expandable: !!node.children && node.children.length > 0, name: node.item, level: level, // 若父节点是Quantity:,则标记该节点属于quantity单选组 radioGroup: node.parent?.item === 'Quantity:' ? 'quantity' : undefined, }; };
2. 重写选中事件处理逻辑
修改原有的选中切换方法,对单选组节点执行互斥选中逻辑,其余节点保持原有多选逻辑:
todoItemSelectionToggle(node: TodoItemFlatNode): void { if (node.radioGroup) { // 单选组逻辑:先清除同组其他已选中节点 const selectedInGroup = this.checklistSelection.selected.filter(n => n.radioGroup === node.radioGroup); selectedInGroup.forEach(n => this.checklistSelection.deselect(n)); // 选中当前节点 this.checklistSelection.toggle(node); } else { // 原有多选逻辑:切换当前节点选中状态,同步父节点状态 this.checklistSelection.toggle(node); this.checkAllParentsSelection(node); } }
3. 调整父节点选中状态计算(可选)
针对Quantity:这类单选组的父节点,调整其选中状态的判断逻辑,使其符合单选组的行为:
// 判断父节点是否所有子节点都选中(针对单选组父节点特殊处理) descendantsAllSelected(node: TodoItemFlatNode): boolean { const descendants = this.treeControl.getDescendants(node); // 若父节点是Quantity:,只要有一个子节点选中即视为"全选" if (node.name === 'Quantity:') { return descendants.some(child => this.checklistSelection.isSelected(child)); } return descendants.every(child => this.checklistSelection.isSelected(child)); } // 判断父节点是否部分选中(针对单选组父节点特殊处理) descendantsPartiallySelected(node: TodoItemFlatNode): boolean { const descendants = this.treeControl.getDescendants(node); if (node.name === 'Quantity:') { // 单选组父节点只有"选中"或"未选中",没有部分选中状态 return false; } return descendants.some(child => this.checklistSelection.isSelected(child)) && !this.descendantsAllSelected(node); }
4. 优化单选组交互体验(可选)
在模板中给单选组节点的复选框添加禁用状态,当同组已有节点选中时,禁用其他节点的复选框,更符合单选交互习惯:
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle> <li class="mat-tree-node"> <button mat-icon-button disabled></button> <mat-checkbox class="checklist-leaf-node" [checked]="checklistSelection.isSelected(node)" <!-- 同组已有选中节点时,禁用当前节点复选框 --> [disabled]="node.radioGroup && checklistSelection.selected.some(n => n.radioGroup === node.radioGroup && n !== node)" (change)="todoItemSelectionToggle(node)">{{node.name}}</mat-checkbox> </li> </mat-tree-node>
内容的提问来源于stack exchange,提问作者LongestOfJohns
相关产品推荐
相关产品推荐

