这是一个宽泛的问题,你给我们的线索很少。所以我简单地指出一个“通用方法”。
1.-在互联网上寻找您喜欢的菜单/子菜单,例如我得到了我在this link 中找到的第一个(我找到的第一个)。你可以寻找一个侧面导航菜单或你想要的那样。一般来说,它是在路上:
<div id="header">
<ul class="nav">
<li><a href="">Home</a></li>
<li><a href="">Services</a>
<ul>
<li><a href="">Submenu1</a></li>
<li><a href="">Submenu2</a></li>
<li><a href="">Submenu3</a></li>
<li><a href="">Submenu4</a>
<ul>
<li><a href="">Submenu1</a></li>
<li><a href="">Submenu2</a></li>
<li><a href="">Submenu3</a></li>
<li><a href="">Submenu4</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="">About</a>
<ul>
<li><a href="">Submenu1</a></li>
<li><a href="">Submenu2</a></li>
<li><a href="">Submenu3</a></li>
<li><a href="">Submenu4</a></li>
</ul>
</li>
<li><a href="">Contact</a></li>
</ul>
</div>
2.-考虑变量、数组和对象。并尝试使用变量重新创建
您会看到菜单“项目”具有标签和href,因此或多或少是{label:"...",href:"..",children:[...]},是的,子项是该对象的简单数组。想象一些像
menu=[
{href:"",label:"Home"},
{href:"",label:"Servicios",children:[
{href:"",label:"Submenu1"},
{href:"",label:"Submenu2"},
{href:"",label:"Submenu3"},
{href:"",label:"Submenu4",children:[
{href:"",label:"Submenu1"},
{href:"",label:"Submenu2"},
{href:"",label:"Submenu3"},
{href:"",label:"Submenu4"}
]},
]},
{href:"",label:"About",children:[
{href:"",label:"Submenu1"},
{href:"",label:"Submenu2"},
{href:"",label:"Submenu3"},
{href:"",label:"Submenu4"}
]},
{href:"",label:"Contact"}
]
我们可以想象这样显示这个对象使用*ngFor 和*ngIf。在 Angular 中,我们不使用 href else routerLink
<div id="header">
<ul class="nav">
<li *ngFor="let item of menu">
<a [routerLink]="item.href">{{item.label}}</a>
<ul *ngIf="item.children">
<li *ngFor="let submenu of item.children">
<a [routerLink]="submenu.href">{{submenu.label}}</a>
<ul *ngIf="submenu.children">
<li *ngFor="let submenu2 of submenu.children">
<a [routerLink]="submenu2.href">{{submenu2.label}}</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
我们可以考虑做一个“递归”组件或符合这个“三个层次”。做一个递归组件不难,可以看this SO
@Component({
selector: '[recursive]',
template: `
<li *ngFor="let item of children">
<a [routerLink]="item.href">{{item.label}}</a>
<ul recursive *ngIf="item.children"
[children]="item.children"
[parent]="self"
[level]="level!=undefined?level+1:0">
</ul>
</li>
`,
})
export class MenuItemComponent {
@Input() level: number;
@Input() label: string;
@Input() children: any[];
@Input() parent: any;
self=this;
}
和我们的 .html 一样
<div id="header">
<ul class="nav" recursive [children]="menu"></ul>
</div>
3.-创建对象。我们已准备好显示菜单,现在是时候使用表格创建对象“菜单”了
与往常一样,我们有一项服务可以获取表格菜单和表格子菜单
/*Imagine return an array like
[{id:1,label:...,href:...},
{id:2,label:...,href:...}..]
*/
getMenu()
{
return this.http.get("myApi/menu");
}
/*Imagine return an array like
[{id:1,label:...,href:...,menuId:1},
{id:2,label:...,href:...,menuId:1}..]
*/
getSubMenu()
{
return this.http.get("myApi/submenu");
}
所以我们可以创建一个新函数来获取这两个表并返回我们的对象“菜单”
getObjectMenu() {
return forkJoin([this.getMenu(), this.getSubMenu()]).pipe(
map(([menu, submenu]: [any[], any[]]) => {
return menu.map((x: any) => ({
...x,
children: submenu.filter(s => s.menuId == x.id)
}));
})
);
}
看到 forkJoin 基于 observable 数组创建了一个 observable。我们在“menu,submenu”中获取两个表,并使用 map 创建一个新对象,即表“menu”加上一个附加属性“children”,其中包含 menuId==x.id 的子菜单
4.-在 Angular 应用程序中使用我们的服务。好了,现在,我们可以在 ngOnInit 中订阅服务并为变量赋值
constructor(private menuService:MenuService){}
ngOnInit()
{
this.menuService.getObjectMenu().subscribe(res=>{
this.menuData=res
})
}
并使用
<div id="header">
<ul class="nav" recursive [children]="menuData"></ul>
</div>
或者,当我们的 service.getObjectMenu() 返回一个 observable 时,我们可以使用管道异步
<div id="header">
<ul class="nav">
<!--see that use menuService.getObjectMenu()|async-->
<li *ngFor="let item of menuService.getObjectMenu()|async">
<a [routerLink]="item.href">{{item.label}}</a>
<ul *ngIf="item.children">
...
</ul>
</div>
//或使用递归
<div id="header">
<ul class="nav" recursive [children]="menuService.getObjectMenu()|async">
</ul>
</div>
更新好吧,获取“菜单”和“子菜单”表确实是“糟糕的设计”,
5.-一般你只会得到一个唯一的表格每个元素的方式{ id: .., href:.., label: .., menuId: .. }
如果 menuId=0 是菜单,否则是子菜单。所以我们可以想象一个函数
getAllMenu()()
{
return this.http.get("myApi/menu");
}
如何创建我们的对象“menuObject”。作为递归,你需要记住你应该有一个被称为自身的函数。嗯,e可以有一个功能
getObjectMenu() {
return this.getAllMenu().pipe(
map((menu: any[]) =>
menu.filter(x=>!x.menuId).map(x => ({
...x,
children: this.getChildren(menu,x.id) //<--here call to function
}))
)
);
}
getChildren(menu:any[],id:number){
return menu.filter(x=>x.menuId==id).map((x:any)=>{
return ({
...x,
children:this.getChildren(menu,x.id) //<--see the function is called to itself
})}
)
}
看到我们所有的 Angular 应用程序都能正常工作,唯一的就是改变“服务”
查看stackblitz