我正在以Angular 创建这个递归嵌套的树视图组件.目标是,无论何时 Select 一个 node ,都应该将样式应用于具有.node-active类的该 node ,而当 Select 其他 node 时,应移除先前应用的样式,并将其添加到当前选定的 node .它对一个子树工作得很好,但当我从其他子树中 Select 其他 node 时,样式也会应用到其他子树.这是Stackblitz LINK-Stackblitz
我正在使用基于当前 node 代码和所选 node 代码的applyStyle函数应用一个类,它对一个子树有效,但对另一个子树无效.任何帮助都是非常有帮助的.
Tree.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-tree',
templateUrl: './Tree.component.html',
styleUrls: ['./Tree.component.css'],
})
export class TreeComponent {
@Input() tree: any;
@Output() selectedValue = new EventEmitter<any>();
public selectedItem: any;
toggleChild(node) {
this.selectedValue.emit(node);
node.showChildren = !node.showChildren;
node.isOpen = !node.isOpen;
}
/* Events are not bubbled up so emitting the parent event on <app-tree>
* when one of the child emits an event - this will create a new EventEmitter per child.
*/
emitOnChildClicked(node) {
this.selectedValue.emit(node);
}
applyStyle(node) {
console.log(node);
this.selectedItem = node.code;
}
}
Tree.component.css
.open-btn {
transform: rotate(90deg);
position: absolute;
left: -30px;
z-index: 10;
}
.close-btn {
left: -30px;
position: absolute;
z-index: 10;
}
.tree li {
list-style-type: none;
margin: 8px;
position: relative;
}
.node-item {
color: var(--lbl-color);
padding: 3px;
}
.green {
background-color: darkred;
}
.node-active {
pointer-events: none;
background: #379df1;
border-radius: 5px;
color: white;
}
.node-item:hover {
background-color: rgb(231, 231, 231);
color: #0f0f0f;
border-radius: 5px;
}
.arrow-btn {
width: 18px;
height: 18px;
}
.tree li::before {
content: '';
position: absolute;
top: -7px;
left: -20px;
border-left: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-radius: 0 0 0 0px;
width: 20px;
height: 15px;
}
.tree li::after {
position: absolute;
content: '';
top: 8px;
left: -20px;
border-left: 1px solid #ccc;
border-top: 1px solid #ccc;
border-radius: 0px 0 0 0;
width: 20px;
height: 100%;
}
.tree li:last-child::after {
display: none;
}
.tree li:last-child:before {
border-radius: 0 0 0 5px;
}
ul.tree > li:first-child::before {
border-left: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.label-container {
display: inline-block;
}
Tree.component.html
<ul *ngIf="tree" class="tree">
<li *ngFor="let node of tree; let i = index">
<div class="label-container" (click)="toggleChild(node)">
<span *ngIf="node.children != 0">
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Icons8_flat_document.svg/512px-Icons8_flat_document.svg.png"
class="arrow-btn"
[ngClass]="node.isOpen ? 'open-btn' : 'close-btn'"
/>
</span>
<span
class="node-item"
(click)="applyStyle(node)"
[ngClass]="{ 'node-active': selectedItem == node.code }"
>
{{ node.name }}
</span>
</div>
<app-tree
*ngIf="node.showChildren"
(selectedValue)="emitOnChildClicked($event)"
[tree]="node.children"
></app-tree>
</li>
</ul>
Tree.mock.ts
export interface TreeNode {
name: string;
showChildren: boolean;
children: any[];
code: string;
}
export const NODES: TreeNode[] = [
{
code: 'AFRI',
name: 'Africa',
showChildren: false,
children: [
{
code: 'ALGE',
name: 'Algeria',
showChildren: false,
children: [
{
code: 'ARIS',
name: 'Algeris',
showChildren: false,
children: [],
},
{
code: 'ACI2',
name: 'Algeria child 2',
showChildren: false,
children: [],
},
],
},
{
code: 'ANGO',
name: 'Angola',
showChildren: false,
children: [],
},
{
code: 'BENI',
name: 'Benin',
showChildren: false,
children: [],
},
],
},
{
code: 'ASIA',
name: 'Asia',
showChildren: false,
children: [
{
code: 'AFGH',
name: 'Afghanistan',
showChildren: false,
children: [
{
code: 'KABU',
name: 'Kabul',
showChildren: false,
children: [],
},
],
},
{
code: 'ARME',
name: 'Armenia',
showChildren: false,
children: [],
},
{
code: 'AZER',
name: 'Azerbaijan',
showChildren: false,
children: [],
},
],
},
{
code: 'EURO',
name: 'Europe',
showChildren: false,
children: [
{
code: 'ROMA',
name: 'Romania',
showChildren: false,
children: [
{
code: 'BUCU',
name: 'Bucuresti',
showChildren: false,
children: [],
},
],
},
{
code: 'HUNG',
name: 'Hungary',
showChildren: false,
children: [],
},
{
code: 'BNIN',
name: 'Benin',
showChildren: false,
children: [],
},
],
},
{
code: 'NOAM',
name: 'North America',
showChildren: false,
children: [],
},
];