65.9K
CodeProject 正在变化。 阅读更多。
Home

Angular2 - 组件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2017年1月17日

Apache

5分钟阅读

viewsIcon

16004

Angular2 - 组件

在哪里可以找到本文的示例代码?

请在 https://github.com/techcoaching/angular2.git 的 "feature/angular2-component" 分支中查看代码。

Angular2 中的组件是什么?

总体来说,为了方便理解,组件就是一个我们想要显示的页面。

在显示我的组件/页面时,是否需要向 Angular 注册?

是的,在 userRoute.ts 中,我们向 Angular 注册当导航到特定 URI 时将渲染哪个组件。

例如

{ path: 'users', component: Users }

这将告诉 Angular,当用户导航到 "<rootUrl>/users" 时,将显示 Users 组件,并且用户列表将如下所示渲染到浏览器:

好的,在代码中,我们只是注册了一个 ts 类(名为 Users)。Angular 如何知道应该渲染哪个 UI?

我明白了,如果我们更深入地查看 Users 类的定义。

@Component({
    templateUrl: "src/users.html"
})
export class Users {}

正如 Users 类的定义中,有一个 @Component 装饰器,其参数对象中有一个 templateUrl 属性。

@Component({
    templateUrl: "src/users.html"
})

Angular 将使用 "src/users.html" 的内容作为 Users 组件的标记。

是否有其他方法指定组件的 HTML 内容?

是的,有两种方法可以指定 Angular 组件的标记:

  • 使用 templateUrl:这是包含该组件标记的 HTML 文件的路径。
  • 使用:template:这包含作为 string 的组件标记。

我将 @Component 装饰器修改如下:

@Component({
    template: "<div>this is inline template</div>"
})

然后 "<root url>/users" 渲染如下:

我应该为我的组件使用 template 还是 templateUrl?

这取决于您。但我建议,如果您的组件需要简短的 HTML(2 或 3 行),那么可以使用 template 属性。否则,我们应该使用 templateUrl 属性。

如何在 Angular 组件中构造模板文件的路径?

例如,对于 Users 组件,路径是 "src/users.html"。

路径是从应用程序根目录计算的。在这种情况下,它与 index.html 在同一个文件夹。

请注意,我们在 index.html 文件中有一个 "<base />" 标签。此标签定义了应用程序如何解析到指定资源的路径(HTML、CSS、图像等)。

那么 "selector" 属性呢?

请暂时忽略此属性,我们将在 "Angular2 - 指令" 文章中再次讨论它。

如何在 HTML 模板文件中显示数据?

我们需要在 Users 类中定义 "users" 属性。此属性包含将在 UI 上显示的用户信息。

以下步骤向您展示了如何在 HTML 文件中显示数据:

users.html 文件中:

<div>
	<table class="table">
		<thead>
			<tr>
				<th>#</th>
				<th>First Name</th>
				<th>Last Name</th>
				<th>Username</th>
				<th>Action</th>
			</tr>
		</thead>
		<tbody>
			<tr *ngFor="let user of users">
				<th scope="row">{{user.id}}</th>
				<td>{{user.firstName}}</td>
				<td>{{user.lastName}}</td>
				<td>{{user.userName}}</td>
				<td>
					<a title=""><i class="fa fa-edit"></i></a>
				</td>
			</tr>
		</tbody>
	</table>
</div>

注意:在 HTML 文件中,我们可以访问 ts 类中的 public 属性(例如:本例中的 users)。

users.ts 中:

@Component({
    templateUrl: "src/users.html"
})
export class Users {
    public users: Array<any> = [
        {id:1, firstName:"Tu", lastName:"Tran", userName:"tutran"},
        {id:2, firstName:"Tu 1", lastName:"Tran", userName:"tutran2"},
        {id:3, firstName:"Tu 2", lastName:"Tran", userName:"tutran3"}
    ];
}

ts 类中,我们需要将其声明为 public 属性并为其设置值。

我尝试将 Users 声明为私有属性。它仍然有效。我的代码有什么问题?

不,您的代码是正确的。

打开与 users.ts 同一个文件夹中的 users.js。我发现(无论是声明 public 还是 private 的 users),生成的 js 都是相同的。

Users = (function () {
	function Users() {
		this.users = [
			{ id: 1, firstName: "Tu", lastName: "Tran", userName: "tutran" },
			{ id: 2, firstName: "Tu 1", lastName: "Tran", userName: "tutran2" },
			{ id: 3, firstName: "Tu 2", lastName: "Tran", userName: "tutran3" }
		];
	}
	return Users;
}());

这就是为什么 publicprivate 不影响页面功能的原因。我猜这是 typescript 编译器 (tsc) 的一个错误。

此时,我们在 Users.ts 类中定义了用户列表。如何将此逻辑提取到外部类并在 users.ts 文件中调用它?

好的,为此,我们需要定义一个新的类(命名为 UserService)并在 Users 类中像下面这样调用它:

userService.ts 中定义 getUsers 方法:

export class UserService {
    public getUsers(): Array<any> {
        let users: Array<any> = [
            { id: 1, firstName: "Tu", lastName: "Tran", userName: "tutran" },
            { id: 2, firstName: "Tu 1", lastName: "Tran", userName: "tutran2" },
            { id: 3, firstName: "Tu 2", lastName: "Tran", userName: "tutran3" }
        ];
        return users;
    }
}

并在 Users 类(在 users.ts 中)中调用它:

export class Users {
    private users: Array<any> = [];
    constructor() {
        let userService = new UserService();
        this.users = userService.getUsers();
    }
}

我们还需要使用 import 语句在 Users 类的顶部导入 UserService 类。

import { UserService } from "./userService";

通过这种方式,我需要手动创建一个新的 User Service 实例,Angular 能为我创建吗?

是的,在 Angular 中,我们有依赖注入 (DI) 的概念。这意味着 Angular 会查找所需的类并为您创建合适的实例。然后,我们可以在该实例上调用相应的方法。

我们还需要声明 UsersUserService 类之间的依赖关系。

好的,听起来很有趣。您能告诉我如何在 Angular 中使用 DI 吗?

好的,首先,我们需要像下面这样修改 Users 类(在 users.ts 中):

export class Users {
    private users: Array<any> = [];
    constructor(userService: UserService) {
        this.users = userService.getUsers();
    }
}

注意

  • Users 类的构造函数中(在 users.ts 中),我们将 userService 声明为 UserService 类型。
  • 并调用此 userServicegetUsers() 来获取用户列表,而无需再创建 UserService 的新实例。

如果我们再次运行应用程序。Angular 会像图片一样抛出一个错误:

Angular 不理解 UserService 是什么。要解决此问题,我们需要在 @Component 装饰器中添加 "providers",如下所示:

@Component({
    ...,
    providers: [UserService]
})

因此,此时 Users 的完整代码如下:

@Component({
    selector: "users",
    templateUrl: "src/users.html",
    providers: [UserService]
})
export class Users {
    private users: Array<any> = [];
    constructor(userService: UserService) {
        this.users = userService.getUsers();
    }
}

让我们再次编译并运行,应用程序运行良好,没有任何错误。

这很好。但我不想在所有组件中都注册 UserService 类。有其他解决方案吗?

是的,在应用程序中,我们可以有一个或多个模块(使用 @NgModule 装饰器声明)。每个组件都在指定的模块中注册。

因此,我们可以在声明了 Users 组件的 @NgModule 中声明 UserService

打开 UserModule 类(在 userModule.ts 中),添加 providers 属性,如下所示:

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        UserRoutes
    ],
    declarations: [Users, CreateUser, EditUser, Layout],
    bootstrap: [Layout],
    providers: [UserService]
})

现在,在 Users 中,我们可以从 @Component 装饰器中删除 providers

@Component({
    selector: "users",
    templateUrl: "src/users.html"
})

编译并刷新浏览器,用户页面运行良好。

我仍然对代码不满意,因为我们直接使用了 UserService 类。我期望应用程序通过 IUserService 接口使用 UserService 的功能。我该怎么做?

不,我们不能将接口注入为依赖项。

export class Users {
    private users: Array<any> = [];
    constructor(userService: IUserService) {
    }
}

这行不通,因为接口是 TypeScript 的定义,JavaScript 不理解接口。这些接口将在将 TypeScript 代码编译成 JavaScript 代码以运行应用程序时被移除。

因此,在运行时,Angular 无法使用接口。

感谢您的阅读。

注意:如果您认为这篇文章对您有帮助,请点赞并与您的朋友分享,我将不胜感激。
© . All rights reserved.