本文概述
- 何时创建单独的Angular组件
- 何时避免创建单独的Angular组件
- 后续步骤:Angular Components 102?
在本文中, 我将通过示例来确定使用Angular组件的正确和不正确的方法。这篇文章应该给你一个清晰的想法:
- Angular组件的定义;
- 什么时候应该创建单独的Angular组件;和
- 不应该创建单独的Angular组件时。
文章图片
在我们开始正确使用Angular组件之前, 我想简要地介绍一下组件主题。一般来说, 每个Angular应用程序默认都有至少一个组件-根组件。从那里开始, 如何设计应用程序取决于我们。通常, 你将为单独的页面创建一个组件, 然后每个页面将包含一个单独的组件的列表。根据经验, 组件必须满足以下条件:
- 必须定义一个包含数据和逻辑的类;和
- 必须与显示最终用户信息的HTML模板相关联。
文章图片
示例应用线框, 其中单独的组件部分已上色
根据上面的屏幕截图, 我们可以清楚地看到应用程序的结构如下所示:
── myTasksApplication
├── components
│├── header-menu.component.ts
│├── header-menu.component.html
│├── task-list.component.ts
│└── task-list.component.html
├── pages
│├── upcoming-tasks.component.ts
│├── upcoming-tasks.component.html
│├── completed-tasks.component.ts
│└── completed-tasks.component.html
├── app.component.ts
└── app.component.html
因此, 让我们将组件文件与上述线框上的实际元素链接起来:
- header-menu.component和task-list.component是可重用的组件, 它们在线框屏幕截图中以绿色边框显示;
- 即将到来的任务。组件和完成的任务。组件是页面, 在上面的线框屏幕截图中以黄色边框显示;和
- 最后, app.component是根组件, 它在线框屏幕截图中显示为红色边框。
输入变量
组件内使用输入变量从父组件传入一些数据。在上面的示例中, 我们可以为task-list.component提供两个输入参数-tasks和listType。因此, 任务将是一个字符串列表, 它将在单独的行上显示每个字符串, 而listType将是即将出现的或已完成的, 这将指示是否选中了该复选框。在下面, 你可以找到有关实际组件外观的一小段代码。
// task-list.component.tsimport { Component, Input } from '@angular/core';
@Component({
selector: 'app-task-list', templateUrl: 'task-list.component.html'
})
export class TaskListComponent{
@Input() tasks: string[] = [];
// List of tasks which should be displayed.
@Input() listType: 'upcoming' | 'completed' = 'upcoming';
// Type of the task list.constructor() { }
}
输出变量
与输入变量类似, 输出变量也可以用于在组件之间传递某些信息, 但这一次是将其传递给父组件。例如, 对于task-list.component, 我们可以输出变量itemChecked。它会通知父组件某个项目是否已选中或未选中。输出变量必须是事件发射器。在下面, 你可以找到有关使用输出变量显示组件外观的一小段代码。
// task-list.component.tsimport { Component, Input, Output } from '@angular/core';
@Component({
selector: 'app-task-list', templateUrl: 'task-list.component.html'
})
export class TaskListComponent{
@Input() tasks: string[] = [];
// List of tasks which should be displayed.
@Input() listType: 'upcoming' | 'completed' = 'upcoming';
// Type of the task list.
@Output() itemChecked: EventEmitter<
boolean>
= new EventEmitter();
@Output() tasksChange: EventEmitter<
string[]>
= new EventEmitter();
constructor() { }/**
* Is called when an item from the list is checked.
* @param selected---Value which indicates if the item is selected or deselected.
*/
onItemCheck(selected: boolean) {
this.itemChecked.emit(selected);
}/**
* Is called when task list is changed.
* @param changedTasks---Changed task list value, which should be sent to the parent component.
*/
onTasksChanged(changedTasks: string[]) {
this.taskChange.emit(changedTasks);
}
}
添加输出变量后可能的task-list.component.ts内容
子组件用法和变量绑定
让我们看一下如何在父组件中使用此组件以及如何进行不同类型的变量绑定。在Angular中, 有两种方法来绑定输入变量:单向绑定(这意味着必须将属性包装在方括号[]中)和双向绑定(这意味着必须将属性包装在方括号和圆括号中) [()]。请看下面的示例, 并查看在组件之间传递数据的不同方式。
<
h1>
Upcoming Tasks<
/h1>
<
app-task-list [(tasks)]="upcomingTasks" [listType]="'upcoming'" (itemChecked)="onItemChecked($event)">
<
/app-task-list>
可能的即将出现的task.task.component.html内容
我们来看一下每个参数:
- 使用双向绑定传递task参数。这意味着, 如果在子组件中更改了tasks参数, 则父组件将在即将到来的Tasks变量上反映这些更改。要允许双向数据绑定, 你必须创建一个输出参数, 该输出参数紧随模板” [inputParameterName] Change” (在本例中为taskChange)。
- 使用单向绑定传递listType参数。这意味着它可以在子组件中进行更改, 但不会反映在父组件中。请记住, 我可以将值” 即将来临” 分配给组件中的一个参数并传递给它, 这没有什么区别。
- 最后, itemChecked参数是一个侦听器函数, 并且在task-list.component上执行onItemCheck时将调用它。如果选中一项, 则$ event的值将为true, 但是如果未选中该项, 则它将的值为false。
何时创建单独的Angular组件 如前所述, 你不应该害怕使用Angular组件, 但绝对应该明智地使用它们。
文章图片
明智地使用Angular组件
那么什么时候应该创建Angular组件呢?
- 如果可以在多个地方重复使用该组件, 则应该始终创建一个单独的组件, 例如我们的task-list.component。我们称它们为可重用组件。
- 如果该组件将使父组件更具可读性并允许他们添加其他测试覆盖范围, 则应考虑创建单独的组件。我们可以称它们为代码组织组件。
- 如果页面的一部分不需要经常更新并且想要提高性能, 则应该始终创建一个单独的组件。这与变更检测策略有关。我们可以称它们为优化组件。
由于我们已经研究了可重用组件的用法, 因此让我们来研究代码组织组件的用法。假设我们有一个注册表格, 并且在表格底部有一个带有条款和条件的框。通常, 法务人员通常非常大, 占用大量空间-在这种情况下, 使用HTML模板。因此, 让我们看一下这个示例, 然后看看我们如何可能对其进行更改。
最初, 我们有一个组件(registration.component), 该组件包含所有内容, 包括注册表格以及条款和条件本身。
<
h2>
Registration<
/h2>
<
label for="username">
Username<
/label>
<
br />
<
input type="text" name="username" id="username" [(ngModel)]="username" />
<
br />
<
label for="password">
Password<
/label>
<
br />
<
input type="password" name="password" id="password" [(ngModel)]="password" />
<
br />
<
div class="terms-and-conditions-box">
Text with very long terms and conditions.
<
/div>
<
button (click)="onRegistrate()">
Registrate<
/button>
将< / code> registration.component < / code> 分为多个组件之前的初始状态
现在, 模板看起来很小, 但是想像一下, 如果我们将” 具有很长的条款和条件的文本” 替换为包含1000个单词以上的实际文本, 这将使文件编辑变得困难且令人不舒服。为此, 我们有一个快速的解决方案-我们可以发明一个新的term-and-conditions.component组件, 其中包含与条款和条件相关的所有内容。因此, 让我们看一下term-and-conditions.component的HTML文件。
<
div class="terms-and-conditions-box">
Text with very long terms and conditions.
<
/div>
新建的< / code> terms-and-conditions.component < / code> HTML模板
现在, 我们可以调整registration.component并在其中使用term-and-conditions.component。
<
h2>
Registration<
/h2>
<
label for="username">
Username<
/label>
<
br />
<
input type="text" name="username" id="username" [(ngModel)]="username" />
<
br />
<
label for="password">
Password<
/label>
<
br />
<
input type="password" name="password" id="password" [(ngModel)]="password" />
<
br />
<
app-terms-and-conditions>
<
/app-terms-and-conditions>
<
button (click)="onRegistrate()">
Registrate<
/button>
使用代码组织组件更新了< / code> registration.component.ts < / code> 模板
恭喜你!我们刚刚将registration.component的大小减少了数百行, 并使其更易于阅读代码。在上面的示例中, 我们更改了组件的模板, 但是相同的原理也可以应用于组件的逻辑。
最后, 对于优化组件, 我强烈建议你阅读本文, 因为它将为你提供了解变更检测所需的所有信息, 以及可以将其应用于哪些特定情况。你不会经常使用它, 但是在某些情况下, 如果不需要时可以跳过对多个组件的常规检查, 那么这将是双赢的性能。
话虽这么说, 我们不应该总是创建单独的组件, 所以让我们看看何时应该避免创建单独的组件。
何时避免创建单独的Angular组件 我建议基于三个要点来创建一个单独的Angular组件, 但是在某些情况下, 我也会避免创建一个单独的组件。
文章图片
太多的组件会使你减速。
再次, 让我们看一下要点, 这将使你轻松理解何时不应该创建单独的组件。
- 你不应为DOM操作创建组件。对于这些, 应该使用属性指令。
- 如果会使代码更加混乱, 则不应创建组件。这与代码组织组件相反。
// log-button.component.tsimport { Component, Input, Output } from '@angular/core';
@Component({
selector: 'app-log-button', templateUrl: 'log-button.component.html'
})
export class LogButtonComponent{
@Input() name: string;
// Name of the button.
@Output() buttonClicked: EventEmitter<
boolean>
= new EventEmitter();
constructor() { }/**
* Is called when button is clicked.
* @param clicked - Value which indicates if the button was clicked.
*/
onButtonClick(clicked: boolean) {
console.log('I just clicked a button on this website');
this.buttonClicked.emit(clicked);
}
}
组件log-button.component.ts错误的逻辑
因此, 此组件随附以下html视图。
<
button (click)="onButtonClick(true)">
{{ name }}<
/button>
错误组件的模板log-button.component.html
如你所见, 上面的示例将起作用, 并且你可以在整个视图中使用以上组件。从技术上讲, 它将满足你的要求。但是, 正确的解决方案是使用指令。这样不仅可以减少必须编写的代码量, 而且还可以将此功能应用于所需的任何元素, 而不仅仅是按钮。
import { Directive } from '@angular/core';
@Directive({
selector: "[logButton]", hostListeners: {
'click': 'onButtonClick()', }, })
class LogButton {
constructor() {}
/**
* Fired when element is clicked.
*/
onButtonClick() {
console.log('I just clicked a button on this website');
}
}
logBu??tton指令, 可以分配给任何元素
现在, 当我们创建指令后, 我们可以在整个应用程序中简单地使用它, 并将其分配给我们想要的任何元素。例如, 让我们重用我们的registration.component。
<
h2>
Registration<
/h2>
<
label for="username">
Username<
/label>
<
br />
<
input type="text" name="username" id="username" [(ngModel)]="username" />
<
br />
<
label for="password">
Password<
/label>
<
br />
<
input type="password" name="password" id="password" [(ngModel)]="password" />
<
br />
<
app-terms-and-conditions>
<
/app-terms-and-conditions>
<
button (click)="onRegistrate()" logButton>
Registrate<
/button>
登录按钮上使用的logBu??tton指令
现在, 我们来看看第二种情况, 在这种情况下, 我们不应该创建单独的组件, 而这与代码优化组件相反。如果新创建的组件使你的代码更复杂, 更大, 则无需创建它。让我们以我们的registration.component为例。一种这样的情况是为带有大量输入参数的标签和输入字段创建单独的组件。让我们来看看这种不好的做法。
// form-input-with-label.component.tsimport { Component, Input} from '@angular/core';
@Component({
selector: 'app-form-input-with-label', templateUrl: 'form-input-with-label.component.html'
})
export class FormInputWithLabelComponent{
@Input() name: string;
// Name of the field
@Input() id: string;
// Id of the field
@Input() label: string;
// Label of the field
@Input() type: 'text' | 'password';
// Type of the field
@Input() model: any;
// Model of the fieldconstructor() { }}
form-input-with-label.component的逻辑
这可能是该组件的视图。
<
label for="{{ id }}">
{{ label }}<
/label>
<
br />
<
input type="{{ type }}" name="{{ name }}" id="{{ id }}" [(ngModel)]="model" />
<
br />
form-input-with-label.component的视图
当然, registration.component中的代码量会减少, 但这是否会使代码的整体逻辑更容易理解和可读?我认为我们可以清楚地看到, 它使代码不必要地比以前更加复杂。
后续步骤:Angular Components 102? 总结一下:不要害怕使用组件;只需确保对要实现的目标有清晰的愿景。上面列出的场景是最常见的场景, 我认为它们是最重要和最常见的场景;但是, 你的方案可能是独特的, 并且取决于你做出明智的决定。希望你学到了足够的知识, 可以做出明智的决定。
如果你想进一步了解Angular的变更检测策略和OnPush策略, 建议阅读Angular变更检测和OnPush策略。它与组件密切相关, 并且正如我在文章中已经提到的那样, 它可以显着提高应用程序的性能。
【Angular组件 — 入门概述】由于组件只是Angular提供的指令的一部分, 因此也很了解属性指令和结构指令将是很棒的。了解所有指令最有可能使程序员更容易一起编写更好的代码。
推荐阅读
- 具有Roots Stack的现代WordPress开发工作流
- 前端(使用Gatsby.js和Node.js进行静态网站更新)
- Laravel零停机时间部署
- 使用Spring Boot实现带有STOMP的WebSocket实现
- 如何创建SSO按钮– Flask登录教程
- Win10系统文件夹怎样进行加密?
- Win10运用迅雷下载提示“资源不足”怎样办?
- Win10系统如何防范IE浏览器运行?
- Win10系统图标显示异常如何处理?