在我之前的 Angular 教程系列之一中,我介绍了 Angular 的基础知识,从安装 CLI 开始,然后讨论如何创建基本组件和实现路由。请查看我关于创建您的第一个 Angular 应用程序:基础知识的文章,了解有关安装 Angular CLI 和其他推荐工具以轻松创建 Angular 应用程序的知识。
我们在该系列中创建的国家/地区信息应用程序非常适合 Angular 入门,但它缺少一些功能。例如,我们将想要向用户显示的信息存储在数组中。但是,在本教程中,我们将超越一小部分数据,让用户搜索 CDNJS 提供的图书馆数据库。
这是我们将要构建的应用程序:
在上一篇文章中,我们创建了一个 LibraryService
类来使用CDNJS API。我们还创建了一个 app-routing.module.ts 文件来为我们的应用提供所有路由逻辑。
在路由逻辑中,您可能已经注意到,当用户位于我们应用程序的主页时,我们告诉 Angular 渲染 HomeComponent
。同样,当用户在输入字段中输入内容后单击列出所有库按钮时,我们告诉 Angular 渲染 LibraryListComponent
。
在本教程中,我们将为 Angular 应用程序创建这两个组件。我们将首先创建 HomeComponent
,然后再创建 LibraryListComponent
。
要使用 Angular CLI 创建 HomeComponent
文件,请移至控制台中 library-finder
应用程序的目录。之后,运行以下命令:
ng generate component home
这将在我们的图书馆查找器应用程序的根目录中创建一个名为 home
的文件夹。该文件夹将包含四个不同的文件。其中三个文件应命名为 home.component.css、home.component.html 和 home.component.ts。
HTML 文件将包含 HomeComponent
的模板代码,CSS 文件将包含该模板的样式信息。 TypeScript 文件将包含 HomeComponent
的逻辑。
以下是 home.component.ts 文件的代码:
import { Component } from '@angular/core'; import { LibraryService } from '../library.service'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent { searchTerm = ''; libraryName = ''; constructor(private libraryService: LibraryService) { } updateTerm(event: any): void { this.searchTerm = event.target.value; } updateName(event: any): void { this.libraryName = event.target.value; } }
如果您阅读了创建第一个 Angular 应用程序系列,您可能已经注意到我们在该系列的第二个教程中创建的 HomeComponent
已从以下位置导入了 OnInit
模块Angular 核心。我们还在 ngOnInit()
方法中初始化了该类中不同属性的值。
这次没有导入这样的模块,因为 HomeComponent
在初始化期间没有获取或设置任何值。除此之外,大多数其他事情都是以类似的方式完成的。
我们首先导入我们之前创建的 LibraryService
类。之后,我们在组件装饰器内设置 selector
、templateUrl
和 styleUrls
的值。请记住,您可以提供多个样式表来设置组件的样式,但只能提供一个模板文件来呈现它。
在 HomeComponent
类定义中,我们定义了两个名为 searchTerm
和 libraryName
的属性。默认情况下,这两个属性的值都设置为空字符串。当用户在相应的输入字段中键入内容时,这些值会在 updateTerm()
和 updateName()
方法内更新。
我们的 HomeComponent
将有两个输入字段和两个链接,它们将充当按钮并将用户带到不同的路径。输入字段将侦听 keyup
事件,并相应地更新 searchTerm
和 libraryName
属性的值。
输入字段旁边的两个链接使用 routerLink
指令将用户带到不同的路径。在第一种情况下,用户转到 /list/{{searchTerm}}
,在第二种情况下,用户转到 /detail/{{libraryName}}
。该路径根据输入字段的当前值动态更新。例如,当有人在第一个输入字段中输入 bootstrap 时,路径变为 /list/bootstrap
,当有人在第一个输入字段中输入 bootstrap 时,路径变为 /detail/jquery
在第二个输入字段中输入 jquery。
这是我们的 home.component.html 文件的完整代码:
<div class="wrapper"> <div class="input-container"> <input type="text" placeholder="Search Term" (keyup)="updateTerm($event)"> <a class="simple" routerLink="/list/{{searchTerm}}">List All Libraries</a> </div> <br> <div class="input-container"> <input type="text" placeholder="Library Name" (keyup)="updateName($event)"> <a class="simple" routerLink="/detail/{{libraryName}}">Show Library Details</a> </div> <br> <h3>Popular Libraries</h3> <div class="library-box" routerLink="/detail/jquery">jQuery</div> <div class="library-box" routerLink="/detail/Chart.js">Chart.js</div> <div class="library-box" routerLink="/detail/sweetalert">SweetAlert</div> </div>
我们还创建了三个不同的框来列出一些流行库的名称。用户将能够直接查看这些库的详细信息,而无需先输入其名称,然后单击显示库按钮。
所有这些元素都被包装在容器 div
元素中,以将它们组合在一起以设置样式。
编写完组件逻辑并创建模板文件后,我们只需更新 CSS 文件即可使 HomeComponent
呈现出来。
这是我用来在模板文件中设置不同元素样式的 CSS。您可以根据自己的喜好更改此处的所有样式规则。
div.wrapper { width: 800px; margin: 20px auto; } h3 { font-size: 1.5em; text-align: center; color: #666; font-family: 'Lato'; } a.simple { background: white; color: black; border: 1px solid black; padding: 5px 10px; font-size: 1.3rem; font-family: 'Lato'; font-weight: 300; border-radius: 5px; text-decoration: none; width: 200px; display: inline-block; text-align: center; } input { border: none; border-bottom: 2px solid #00ccff; font-size: 1.5rem; outline: none; font-family: 'Lato'; font-weight: 300; margin-right: 100px; width: 450px; } input:focus { border-bottom: 2px solid #ccff00; } div.library-box { font-family: 'Lato'; color: white; background: purple; width: 200px; height: 70px; text-align: center; padding-top: 30px; font-size: 2em; border-radius: 4px; display: inline-block; margin: 20px; } div.library-box:hover { background: black; cursor: pointer; }
CSS 文件中的所有内容都是不言自明的。我们将包装器 div
的宽度设置为固定的 800 px 值。当用户将鼠标悬停在带有流行库名称的底部框上时,其背景颜色会更改为黑色。
正如我之前提到的,LibraryListComponent
将用于列出包含从当前路径中提取的搜索词的所有库。您可以通过在命令行执行以下语句来快速生成该组件所需的所有文件:
ng generate component library-list
就像我们的 home 组件一样,此命令将在根目录中创建一个名为 library-list
的文件夹。该文件夹内将有四个文件,但我们只需要担心其中三个:library-list.component.css、library-list.component.html、和library-list.component.ts。
组件加载后,我们将尝试获取与 URL 中提供的搜索词相关的库列表。这意味着我们还必须从 @angular/core
导入 OnInit
以及 Component
。
导入 ActivatedRoute
允许我们使用与当前加载的组件关联的路由的所有信息。这样,我们就可以轻松地从当前路径中提取搜索词。从 Angular 导入不同的依赖项后,我们继续导入 LibraryService
类。
像往常一样,组件装饰器存储 LibraryListComponent
的选择器值、模板 URL 和样式表路径。
在 ngOnInit()
方法中,我们调用 getLibrary()
方法。 getLibrary()
方法进一步使用 searchLibraries()
方法从 LibraryService
获取我们所有的结果。然后,这些结果存储在类定义顶部声明的 libraries
数组中。
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { LibraryService } from '../library.service'; @Component({ selector: 'app-library-list', templateUrl: './library-list.component.html', styleUrls: ['./library-list.component.css'] }) export class LibraryListComponent implements OnInit { libraries = []; constructor( private route: ActivatedRoute, private libraryService: LibraryService ) { } ngOnInit() { this.getLibrary(); } getLibrary(): void { const library: string = this.route.snapshot.paramMap.get('search'); this.libraryService.searchLibraries(library) .then((data: any) => { data.results.forEach(function (result) { this.libraries.push({ 'name': result.name, 'version': result.version, 'description': result.description }); }, this); }); } }
在本教程中,我们成功创建了图书馆查找器应用程序的 HomeComponent
。这将允许用户在 CDNJS 数据库中搜索不同的库。 HomeComponent
本身并不是很有用。因此,我们将创建另外两个组件,名为 LibraryListComponent
和 LibraryDetailsComponent
。
我们已经更新了 LibraryListComponent
的 TypeScript 文件。我们将在下一个教程中更新 HTML 模板和 CSS 文件。如果您对本教程有任何疑问,请在评论中告诉我。