按照MVC的开发理论,在C层与V层的分工中,应该这样:① C层来确定V层显示什么样的数据;②V层决定显示数据的格式(样式)。也就是说:像`系统的名称`是什么,除了首页外还有几个菜单项,这些都应该是C层来负责的。 ## 分层 按上述的理论,我们将V层本应该存在于C层的信息迁移过来。 ### C层 nav/nav.component.ts ``` export class NavComponent implements OnInit { /*标题*/ title: string; ① /*菜单项*/ menus = new Array<{ url: string; name: string }➊>(); ② constructor() { } ngOnInit() { this.title = '教务管理系统'; ③ this.menus.push({url: 'teacher', name: '教师管理'}); ③ this.menus.push({url: 'klass', name: '班级管理'}); ③ } } ``` * ➊ Array是一个容器,在进行初始化时,我们需要为其定义类型。在定义类型时,可以使用`对象`声明的方法来替待使用`类`进行声明的方式。 ### V层 nav/nav.component.html ``` <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <a class="navbar-brand" routerLink="">{{title}}①</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" routerLink="">首页 <span class="sr-only">(current)</span></a> </li> <li class="nav-item" *ngFor="let menu of menus"②> <a class="nav-link" routerLink="{{menu.url}}③">{{menu.name}}④</a> </li> </ul> </div> </nav> ``` #### 测试 对nav组件进行测试 ``` Failed: Template parse errors: Can't bind to 'routerLink' since it isn't a known property of 'a'. (" ``` 提示没有找到routerLink属性,则加入路由模块来修正此问题。 nav/nav.component.spec.ts ``` TestBed.configureTestingModule({ declarations: [NavComponent], imports: [RouterTestingModule] }) ``` 测试通过 ## 集成测试 最后使用`ng serve`来启动项目,并查看其在系统中的表现效果。 ![](https://img.kancloud.cn/df/36/df36f7bd459c61cfea79edcbf9319df1_766x476.png) 我们发现有个小的问题:无论当前是哪个功能界面,被点亮的永远是`首页`。这是由于在以下样式决定的: nav/nav.component.html ``` <li class="nav-item active①"> <a class="nav-link" routerLink="">首页 <span class="sr-only">(current)</span></a> </li> ``` * ① active样式决定了其点亮的特定 ### RouterLinkActive angular为我们提供了RouterLinkActive来解决此问题,当以RouterLinkActive标识的链接被选中时,会自动将RouterLinkActive的值添加加宿主元素的样式中,比如我们可以这样用: ``` <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav"> <li class="nav-item" routerLinkActive="active"➊> <a class="nav-link" routerLink="">首页 <span class="sr-only">(current)</span></a> </li> <li class="nav-item" *ngFor="let menu of menus" routerLinkActive="active"➊> <a class="nav-link" routerLink="{{menu.url}}">{{menu.name}}</a> </li> </ul> </div> ``` * ➊ 当宿主节点(元素)或宿主节点下的子节点中的路由被选中时,将active添加到宿主节点的class中。 #### 测试: ![](https://img.kancloud.cn/c2/0c/c20c7810726e4b0cde1efe00fa8397d8_1003x343.png) 但当前我们选择了班级管理,为什么首页也被点亮了呢?这是因为班级管理的地址为`/klass`,而`/klass`是基于首页的路由地址`<空>`的,所以此时的路由实际是:首页`<空>`的子路由`klass`(想想我们配置路由的过程),所以此时班级管理及首页都被点亮是正确的。如果我们并不想点亮父路由,则可以使用设置`routerLinkActiveOptions`来解决这个问题: ``` <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}"➊> <a class="nav-link" routerLink="">首页 <span class="sr-only">(current)</span></a> </li> ``` * ➊ routerLinkActiveOptions = 路由链接激活选项, exact = 严格的、精确的 加入该选择后,当点班级管理或是教师管理时,首页就不会被点亮了。 ![](https://img.kancloud.cn/30/91/309137844841ae0f447421b9d35cf36d_435x151.png) ## 测试 最后在收尾前我们将所有的`f`由测试代码中去除,并运行`ng test`看是否当前的开发对历史功能造成了影响 。 ``` Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 11 of 14 SUCCESS (0 secs / 0.443 secs) Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 14 of 14 SUCCESS (0.57 secs / 0.516 secs) TOTAL: 14 SUCCESS TOTAL: 14 SUCCESS ``` 未发生其它异常,放宽心的收工。 # 参考文档 | 名称 | 链接 | 预计学习时长(分) | | --- | --- | --- | | 源码地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step4.2.3](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step4.2.3) | - | [https://angular.io/api/router/RouterLinkActive](https://angular.io/api/router/RouterLinkActive)