ng-组件

几乎所有前端框架都在玩“组件化”,而且最近都不约而同地选择了“标签化”这种思路,Angular 也不例外。
对新版本的 Angular 来说,一切都是围绕着“组件化”展开的,组件是 Angular 的核心概念模型。

组件的定义
以下是一个最简单的 Angular 组件定义:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'itcast';
}
@Component:这是一个 Decorator(装饰器),其作用类似于 Java 里面的注解。Decorator 这个语言特性目前(2017-10)处于 Stage 2(草稿)状态,还不是 ECMA 的正式规范。selector:组件的标签名,外部使用者可以这样来使用这个组件:。默认情况下,ng 命令生成出来的组件都会带上一个 app 前缀,如果你不喜欢,可以在 angular-cli.json 里面修改 prefix 配置项,设置为空字符串将会不带任何前缀。templateUrl:引用外部的 HTML 模板。如果你想直接编写内联模板,可以使用 template,支持 ES6 引入的“模板字符串”写法。styleUrls:引用外部 CSS 样式文件,这是一个数组,也就意味着可以引用多份 CSS 文件。export class AppComponent:这是 ES6 里面引入的模块和 class 定义方式。
组件的模板
- 内联模板
- 模板文件
你可以在两种地方存放组件模板。 你可以使用template属性把它定义为内联的,或者把模板定义在一个独立的 HTML 文件中, 再通过@Component装饰器中的templateUrl属性, 在组件元数据中把它链接到组件。
无论用哪种风格,模板数据绑定在访问组件属性方面都是完全一样的。
具体模板语法参考:模板语法
组件通信
组件就像零散的积木,我们需要把这些积木按照一定的规则拼装起来,而且要让它们互相之间能进行通讯,这样才能构成一个有机的完整系统。
在真实的应用中,组件最终会构成树形结构,就像人类社会中的家族树一样:

在树形结构里面,组件之间有几种典型的关系:父子关系、兄弟关系、没有直接关系。
相应地,组件之间有以下几种典型的通讯方案:
- 直接的父子关系:父组件直接访问子组件的 public 属性和方法。
- 直接的父子关系:借助于 @Input 和 @Output 进行通讯
- 没有直接关系:借助于 Service 单例进行通讯。
- 利用 cookie 和 localstorage 进行通讯。
- 利用 session 进行通讯。
无论你使用什么前端框架,组件之间的通讯都离开不以上几种方案,这些方案与具体框架无关。
父子通信:Input Down
参考文档:https://angular.io/guide/component-interaction#pass-data-from-parent-to-child-with-input-binding
- 父组件通过子组件标签传递属性
- 子组件在内部声明
@Input接收
- Input 是单向的
- 父组件如果把数据改了,子组件也会更新
- 但是反之不会
- 有一个例外,引用类型修改
下面是一个示例:
子组件:
import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'app-hero-child',
template: `
<h3>{{hero.name}} says:</h3>
<p>I, {{hero.name}}, am at your service, {{masterName}}.</p>
`
})
export class HeroChildComponent {
// 声明接收父组件传递的数据
@Input() hero: Hero;
@Input('master') masterName: string; // 接收 master 重命名为 masterName
}
父组件:
import { Component } from '@angular/core';
import { HEROES } from './hero';
@Component({
selector: 'app-hero-parent',
template: `
<h2>{{master}} controls {{heroes.length}} heroes</h2>
<!-- 在子组件标签上传递数据 -->
<app-hero-child *ngFor="let hero of heroes"
[hero]="hero"
[master]="master">
</app-hero-child>
`
})
export class HeroParentComponent {
heroes = HEROES;
master = 'Master';
}
父子通信:Output Up
参考文档:https://angular.io/guide/component-interaction#parent-listens-for-child-event
@Output 的本质是事件机制,我们可以利用它来订阅子组件上发布的事件,子组件上这样写:
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-voter',
template: `
<h4>{{name}}</h4>
<button (click)="vote(true)" [disabled]="voted">Agree</button>
<button (click)="vote(false)" [disabled]="voted">Disagree</button>
`
})
export class VoterComponent {
@Input() name: string;
@Output() onVoted = new EventEmitter<boolean>();
voted = false;
vote(agreed: boolean) {
this.onVoted.emit(agreed); // 传递的数据就是事件对象
this.voted = true;
}
}
在父组件中订阅处理:
import { Component } from '@angular/core';
@Component({
selector: 'app-vote-taker',
template: `
<h2>Should mankind colonize the Universe?</h2>
<h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
<app-voter *ngFor="let voter of voters"
[name]="voter"
(onVoted)="onVoted($event)">
</app-voter>
<!-- $event在这里是自定义事件对象,接收到的是子组件内部发布事件传递的数据 -->
`
})
export class VoteTakerComponent {
agreed = 0;
disagreed = 0;
voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'];
onVoted(agreed: boolean) {
agreed ? this.agreed++ : this.disagreed++;
}
}
父子通信:父组件直接访问子组件 public 成员
参考文档:https://angular.io/guide/component-interaction#parent-interacts-with-child-via-local-variable
对于有直接父子关系的组件,父组件可以直接访问子组件里面 public 型的属性和方法,示例代码片段如下:
<app-foo #child></app-foo>
<button (click)="child.increment()">调用子组件的方法</button>
显然,子组件里面必须暴露一个 public 型的 childFn 方法,就像这样:
export class FooComponent implements OnInit {
public message: string = 'foo message'
public count: number = 0
constructor() { }
public increment (): void {
this.count++
}
ngOnInit() {
}
}
以上是通过在模板里面定义局部变量的方式来直接调用子组件里面的 public 型方法。在父组件的内部也可以访问到子组件的实例,需要利用到 @ViewChild 装饰器,示例如下:
@ViewChild(ChildComponent)
private childComponent: ChildComponent;
关于 @ViewChild 在后面的内容里面会有更详细的解释。
很明显,如果父组件直接访问子组件,那么两个组件之间的关系就被固定死了。父子两个组件紧密依赖,谁也离不开谁,也就都不能单独使用了。所以,除非你知道自己在做什么,最好不要直接在父组件里面直接访问子组件上的属性和方法,以免未来一改一大片。
没有直接关系通信:Service 单例
参考文档:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

利用 Cookie 和 localStorage 进行通信

利用 Session 进行通信

小结
组件间的通讯方案是通用的,无论你使用什么样的前端框架,都会面临这个问题,而解决的方案无外乎本文所列出的几种。
组件生命周期

ngOnChanges()
ngOnInit()
- 只执行一次
ngDoCheck()
ngAfterContentInit()
- 只执行一次
ngAfterContentChecked()
ngAfterViewInit()
- 只执行一次
ngAfterViewChecked()
ngOnDestroy()
- 只执行一次
Angular 一共暴露了8个“钩子”,构造函数不算。
并没有组件或者指令会实现全部钩子。
绿色的4个钩子可能会被执行很多次,紫色的只会执行一次。
Content 和 View 相关的4个钩子只对组件有效,指令上不能使用。因为在新版本的 Angular 里面,指令不能带有 HTML 模板。指令没有自己的 UI,当然就没有 View 和 Content 相关的“钩子”了。
请不要在生命周期钩子里面实现复杂的业务逻辑,尤其是那4个会被反复执行的钩子,否则一定会造成界面卡顿。
动态组件
!> 注意:用代码动态创建组件这种方式在一般的业务开发里面不常用,而且可能存在一些隐藏的坑,如果你一定要用,请小心避雷。
组件内容分发
第三方组件库
ng-组件的更多相关文章
- ng组件通讯的几种方式
通过输入型绑定把数据从父组件传到子组件. 如<app-hero-child *ngFor="let hero of heroes" [hero]="hero&qu ...
- Flume NG Getting Started(Flume NG 新手入门指南)
Flume NG Getting Started(Flume NG 新手入门指南)翻译 新手入门 Flume NG是什么? 有什么改变? 获得Flume NG 从源码构建 配置 flume-ng全局选 ...
- 2021 年最值得推荐的 7 个 Angular 前端组件库 - DevUI
摘要:DevUI 是一款面向企业中后台产品的开源前端解决方案,它倡导沉浸.灵活.至简的设计价值观,提倡设计者为真实的需求服务,为多数人的设计,拒绝哗众取宠.取悦眼球的设计.如果你正在开发 ToB 的工 ...
- Angular移除不必要的$watch之性能优化
双向绑定是Angular的核心概念之一,它给我们带来了思维方式的转变:不再是DOM驱动,而是以Model为核心,在View中写上声明式标签.然后,Angular就会在后台默默的同步View的变化到Mo ...
- Flume 中文入门手冊
原文:https://cwiki.apache.org/confluence/display/FLUME/Getting+Started 什么是 Flume NG? Flume NG 旨在比起 Flu ...
- [转]Angular移除不必要的$watch之性能优化
双向绑定是Angular的核心概念之一,它给我们带来了思维方式的转变:不再是DOM驱动,而是以Model为核心,在View中写上声明式标签.然后,Angular就会在后台默默的同步View的变化到Mo ...
- angular schametics 使用记录
什么是 schametics Schematics是Angular团队发布的一个代码生成工具.它提供了API,可以操作文件并在Angular项目中添加新的依赖项,ng cli 创建模板就是用它. 它也 ...
- 现代富文本编辑器Quill的内容渲染机制
DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师.官方网站:devui.designNg组件库:ng-devui(欢迎S ...
- 手把手教你使用Rollup打包📦并发布自己的工具库🔧
DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站:devui.design Ng组件库:ng-devui(欢 ...
- 大厂是如何用DevCloud流水线实现自动化部署Web应用的?
DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站:devui.design Ng组件库:ng-devui(欢 ...
随机推荐
- 曹工说Spring Boot源码(16)-- Spring从xml文件里到底得到了什么(aop:config完整解析【上】)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 通俗易懂的ref和out区别
ref 和 out 是C#开发中经常用到的两个关键字,但是很多人没有搞清楚这两个关键字的具体区别,下面我们来说一下这两个关键的区别. 零. ref 与 out 的异同 相同: 都是按地址传递: 使用后 ...
- 多用as少用强制类型转换
在 C# 中存在一个名叫静态类型检查的机制,这个机制可以让编译器帮助我们把类型不服的用法找出来,从而使得应用程序在运行期间加少一些类型检查的操作.但是有时候我们还是需要进行运行期类型检查,比如我们在设 ...
- 关于在osgearth 中 出现 arial.ttf : file not handled 的问题
这是由于配置osg时 freetype 插件没有配置到位. 我个人的解决方法 打开CMAKE,点击advance,不勾选OSG_TEXT_USE_FONTCONFIG. 同时将freetype路径设置 ...
- Classmethod and Staticmethod - Python 类方法 和 静态方法
classmethod and staticmethod classmethod 的是一个参数是类对象 cls (本类,或者子类), 而不是实例对象 instance (普通方法). classmet ...
- CNN中的feature map
个人学习CNN的一些笔记,比较基础,整合了其他博客的内容 feature map的理解在cnn的每个卷积层,数据都是以三维形式存在的.你可以把它看成许多个二维图片叠在一起(像豆腐皮竖直的贴成豆腐块一样 ...
- php 搭建webSocket
<?php //2.设计一个循环挂起WebSocket通道,进行数据的接收.处理和发送 //对创建的socket循环进行监听,处理数据 function run(){ //死循环,直到socke ...
- 数据算法 --hadoop/spark数据处理技巧 --(9.基于内容的电影推荐 10. 使用马尔科夫模型的智能邮件营销)
九.基于内容的电影推荐 在基于内容的推荐系统中,我们得到的关于内容的信息越多,算法就会越复杂(设计的变量更多),不过推荐也会更准确,更合理. 本次基于评分,提供一个3阶段的MR解决方案来实现电影推荐. ...
- MarkdownPad2 安装以及出现的错误(This view has crashed)
在这里首先感谢 堃堃5love 的解决办法 原文链接:https://blog.csdn.net/kunkun5love/article/details/79495618 声明:写这个是为了以后遇见问 ...
- 想学大学计算机课?这 37 门 CS 专业必修课,了解一下
最近,不少高校延迟开学,大家只能宅家上网课. 有一些朋友,想趁此期间,多学点计算机的专业课,却不知从何学起. 211,985大学的计算机专业课都是经过授课教师精心安排的,从大一到大四,课程合理设置,循 ...