示例应用程序线框图与单独的组件部分着色< / div >
根据上面的截图, 我们可以清楚地看到应用程序的结构是这样的:
──myTasksApplication
├──组件
│├──header-menu.组件.ts
│├──header-menu.组件.html
│├──rammstein.组件.ts
│││任务列表.组件.html
├──页面
│├──即将完成的任务.组件.ts
│├──即将完成的任务.组件.html
│├──已完成的任务.组件.ts
│││完成的任务.组件.html
├──应用.组件.ts
└──应用.组件.html
因此,让我们将组件文件与上面线框图上的实际元素链接起来:
-
header-menu.组件
和 任务列表.组件
是可重用的组件,在线框截图中以绿色边框显示;
-
接下来要完成的任务.组件
和 完成的任务.组件
are 页面, which are displayed with a yellow border in the wireframe screenshot above; 和
- 最后,
应用程序.组件
是根组件,在线框截图中显示为红色边框.
因此,话虽如此,我们可以为每个组件指定单独的逻辑和设计. 基于上面的线框图,我们有两个重用一个组件的页面任务列表.组件
. 问题来了——我们如何指定在特定页面上显示什么类型的数据? 幸运的是, 我们不用担心这个, 因为当你创建一个组件时, 你也可以指定 Input 和 Output 变量.
在组件中使用输入变量来传递来自父组件的一些数据. 在上面的例子中,我们可以有两个输入参数 任务列表.组件
—任务
和 listType
. 因此, 任务
将是一个字符串列表,它将在单独的行上显示每个字符串,而 listType
要么 即将到来的 or 完成,这将指示复选框是否被选中. 下面是一小段代码片段,说明了实际组件的外观.
/ /任务列表.组件.ts
从“@angular/core”中导入{Component, Input};
@ 组件 ({
选择器:“应用程序-任务列表”,
templateUrl:“任务列表.组件.html的
})
导出类TaskListComponent {
@Input() 任务: string[] = []; // List of 任务 which 应该 be displayed.
@Input() listType: “即将” | '完成' = “即将”; // Type of the task list.
构造函数(){}
}
输出变量
类似于输入变量, 输出变量还可以用于在组件之间传递一些信息, 但这次是父组件. 例如,对于 任务列表.组件
,我们可以有输出变量 itemChecked
. 它将通知父组件是否选中或未选中某个项. 输出变量必须为 事件发射器. 下面,您可以找到一小段代码片段,其中显示了使用输出变量时组件的外观.
/ /任务列表.组件.ts
从“@angular/core”中导入{Component, Input, Output};
@ 组件 ({
选择器:“应用程序-任务列表”,
templateUrl:“任务列表.组件.html的
})
导出类TaskListComponent {
@Input() 任务: string[] = []; // List of 任务 which 应该 be displayed.
@Input() listType: “即将” | '完成' = “即将”; // Type of the task list.
@Output() itemChecked: EventEmitter = new EventEmitter();
@Output() 任务Change: EventEmitter = new EventEmitter();
构造函数(){}
/**
当列表中的项被选中时调用.
* @param selected——值,表示项目是被选中还是被取消选中.
*/
onItemCheck(选中:boolean) {
这.itemChecked.发出(选择);
}
/**
当任务列表被更改时调用.
* @param changedTasks——修改任务列表的值,该值应该发送给父组件.
*/
onTasksChanged(changedTasks: string[]) {
这.taskChange.发出(changedTasks);
}
}
可能的
任务列表.组件.ts
添加输出变量后的内容< / div >
子组件使用和变量绑定
让我们看一下如何在父组件中使用这个组件,以及如何进行不同类型的变量绑定. 在角, 有两种方法可以绑定输入变量—单向绑定, 这意味着该属性必须用方括号括起来 []
以及双向绑定,这意味着必须将属性包装在方括号和圆括号中 [()]
. 看看下面的例子,看看数据在组件之间传递的不同方式.
Upcoming Tasks
<应用程序-任务列表 [(任务)]="即将到来的Tasks" [listType]="“即将”" (itemChecked)="onItemChecked(美元的事件)">应用程序-任务列表>
可能的
接下来要完成的任务.组件.html
内容< / div >
让我们来看看每个参数:
- 的
任务
参数使用双向绑定传递. 这意味着, 如果在子组件中更改了任务参数, 父组件将把这些更改反映到 即将到来的Tasks
变量. 允许双向数据绑定, 您必须创建一个输出参数, 它跟在模板" [inputParameterName]Change "后面, 在这种情况下 任务Change
.
- 的
listType
参数使用单向绑定传递. 这意味着它可以在子组件中更改, 但它不会反映在父组件中. 记住,我可以赋值 “即将”
到组件内的一个参数,并传递它,这没有什么区别.
- 最后,
itemChecked
参数是一个侦听器函数,它将在任何时候被调用 onItemCheck 在 任务列表.组件
. 如果选中了某项, 美元的事件
会保持这个值 真正的
,但是,如果未选中,它将保存该值 假
.
如你所见, 在一般情况下, 角提供了一种在多个组件之间传递和共享信息的好方法, 所以你不应该害怕使用它们. 只是要确保明智地使用它们,不要过度使用它们.
何时创建一个单独的角组件
如前所述, 你不应该害怕使用角组件, 但你绝对应该明智地使用它们.
< / div >
明智地使用角组件< / div >
所以,当 你应该 创建角组件?
- 你 应该总是 如果组件可以在多个地方被重用,就创建一个单独的组件
任务列表.组件
. 我们称之为 可重用组件.
- 你 应该考虑 创建一个单独的组件,如果该组件将使父组件更具可读性,并允许它们添加额外的测试覆盖. 我们可以打电话给他们 代码组织组件.
- 你 应该总是 如果页面的一部分不需要经常更新,并且希望提高性能,则创建一个单独的组件. 这与变更检测策略有关. 我们可以打电话给他们 优化组件.
这三个规则帮助我确定是否需要创建一个新组件, 它们会自动给我一个组件角色的清晰视图. 在理想的情况下, 创建组件时, 您应该已经知道它在应用程序中的角色.
因为我们已经学习了的用法 可重用组件,我们来看看的用法 代码组织组件. 假设我们有一个注册表单,在表单的底部,我们有一个带有 条款与条件. 通常, 法律术语往往非常庞大, 在这种情况下,占用了很多空间, 在HTML模板中. 那么,让我们来看看这个例子,然后看看我们如何可能改变它.
一开始,我们有一个分量-登记.组件
-容纳一切, 包括注册表格以及条款和条件本身.
Registration
文本非常长的条款和条件.
Initial state before separating 登记.组件 into multiple 组件s< / div >
模板现在看起来很小,但是想象一下如果我们替换 “带有很长条款和条件的文本” 对于超过1000个单词的实际文本,这将使文件的编辑变得困难和不舒服. 我们有一个快速的解决方案——我们可以发明一个新的组件 条款和条件.组件
,其中包含与条款和条件有关的所有内容. 让我们看一下HTML文件 条款和条件.组件
.
文本非常长的条款和条件.
Newly created 条款和条件.组件 HTML template< / div >
现在我们可以调整 登记.组件
然后使用 条款和条件.组件
在它的内部.
Registration
<应用程序-条款和条件>应用程序-条款和条件>
Updated 登记.组件.ts template with code organization 组件< / div >
祝贺你! 我们刚刚减小了 登记.组件
减少了数百行,使代码更容易阅读. 在上面的例子中, 我们对组件的模板进行了更改, 但是同样的原理也可以应用到组件的逻辑上.
最后,对于 优化组件,我强烈建议你通过 这篇文章, 因为它将为您提供理解变更检测所需的所有信息, 以及你可以将其应用于哪些具体情况. 你不会经常使用它, 但可能会有一些情况, 如果你可以在没有必要的时候跳过对多个组件的定期检查, 这是一个双赢的表现.
话虽如此, 我们不应该总是创建单独的组件, 因此,让我们看看在什么情况下应该避免创建单独的组件.
何时避免创建单独的角组件
基于这三点,我建议创建一个单独的角组件, 但在某些情况下,我也会避免创建单独的组件.
< / div >
太多的组件会减慢你的速度.< / div >
再一次,让我们来看看要点,这些要点可以让你很容易地理解 不应该 创建一个单独的组件.
- 你 不应该 为DOM操作创建组件. 对于这些,您应该使用 属性指示.
- 你 不应该 创建组件,如果它将使您的代码更混乱. 这是相反的 代码组织组件.
现在,让我们仔细看看,并在示例中检查这两种情况. 假设我们希望有一个按钮,在点击消息时记录该消息. 这可能是错误的,并且可能为此特定功能创建单独的组件, 哪一个可以容纳特定的按钮和操作. 让我们先检查一下不正确的方法:
/ / log键.组件.ts
从“@angular/core”中导入{Component, Input, Output};
@ 组件 ({
选择器:“应用程序-log键”,
templateUrl:“log键.组件.html的
})
导出类LogButtonComponent {
@Input() name: string; // Name of the button.
@Output() buttonClicked: EventEmitter = new EventEmitter();
构造函数(){}
/**
当按钮被点击时调用.
* @param clicked -表示按钮是否被单击的值.
*/
onButtonClick(click: boolean) {
控制台.log(“我刚刚点击了这个网站上的一个按钮”);
这.buttonClicked.发出(点击);
}
}
不正确组件的逻辑
log键.组件.ts
< / div >
相应地,该组件伴随着下面的html视图.
错误组件模板
log键.组件.html
< / div >
如你所见, 上面的例子可以工作, 您可以在整个视图中使用上述组件. 从技术上讲,它会做你想做的事. 但正确的解决方案是使用指令. 这样不仅可以减少必须编写的代码量,还可以将此功能应用于所需的任何元素, 不仅仅是按钮.
从“@angular/core”中导入{Directive};
@Directive ({
选择器:“[logButton]”,
hostListeners: {
“点击”:“onButtonClick()”,
},
})
类LogButton {
构造函数(){}
/**
*当元素被点击时触发.
*/
onButtonClick () {
控制台.log(“我刚刚点击了这个网站上的一个按钮”);
}
}
logButton
指令,它可以被赋值给任何元素< / div >
现在我们创建了指令, 我们可以简单地在整个应用程序中使用它,并将其分配给我们想要的任何元素. 例如,让我们重用我们的 登记.组件
.
Registration
<应用程序-条款和条件>应用程序-条款和条件>
logButton
在注册表格按钮上使用的指令< / div >
现在, 我们来看看第二种情况, 其中我们不应该创建单独的组件, 这和 代码优化组件. 如果新创建的组件使您的代码更复杂和更大, 没有必要创建它. 让我们以……为例 登记.组件
. 其中一种情况是为标签和带有大量输入参数的输入字段创建一个单独的组件. 让我们来看看这个坏习惯.
/ / form-input-with-label.组件.ts
从“@angular/core”中导入{Component, Input};
@ 组件 ({
选择器:“应用程序-form-input-with-label”,
templateUrl:“form-input-with-label.组件.html的
})
导出类formminputwithlabel组件 {
@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 field
构造函数(){}
}
逻辑
form-input-with-label.组件
< / div >
这可以是这个组件的视图.
视野
form-input-with-label.组件
< / div >
当然,代码的数量会减少 登记.组件
,但它是否使代码的整体逻辑更容易理解和可读性? 我认为我们可以清楚地看到,它使代码比以前不必要地更加复杂.
下一步:角组件?
To summarize: Don’t be afraid to use 组件s; just make sure that you have a clear vision about what you want to achieve. 我上面列出的场景是最常见的, 和 I consider them to be the most important 和 common ones; however, 你的情况可能是独特的,这取决于你做出明智的决定. 我希望你已经学到了足够的东西,可以做出正确的决定.
如果你想了解更多关于角的变更检测策略和OnPush策略, 我推荐阅读 角变化检测和OnPush策略. 它与组件和密切相关, 正如我在帖子中提到的, 它可以显著提高应用程序的性能.
因为组件只是角提供的指令的一部分, 要是能了解一下就太好了 属性指示 和 结构指示. 理解所有的指令很可能使程序员更容易写出更好的代码.
< / div >< / div >< / div >< / div >
< / div >
了解基本知识
角中有什么类型的指令啊?
有组件指令、属性指令和结构指令.
< / div >< / div >
什么是角选择器?
选择器是在模板中调用组件的一种方式. 它是组件的唯一标识符.
< / div >< / div >
什么是角组件?
组件是一个带有模板的指令,它允许在角应用中构建UI模块. 组件总是有一个模板、一个选择器,并且可能有也可能没有单独的样式. 使用@Component声明组件.
< / div >< / div >
什么是角模板?
角模板定义组件的UI.
< / div >< / div >
角中的属性指令是什么?
属性指令改变DOM元素出现或行为的方式. 属性没有模板,是用@Directive声明的.
< / div >< / div >
什么是角?
角是一个允许用户轻松构建web应用程序的平台. 它是基于TypeScript的.
< / div >< / div >
什么是TypeScript?
TypeScript是一种脚本语言,它起源于JavaScript,并且是JavaScript的超集.
< / div >< / div >< / div >< / div >
标签
< / div >< / div >< / div >< / div >
聘请Toptal这方面的专家.< / div >
现在雇佣< / div >< / div >