组件交互方式
- 通过输入型绑定把数据从父组件传到子组件 @input装饰器是从父组件中传递过来的属性传递到子组件中,即@input写在了子组件里面
- 通过setter监测输入属性值发生的变化
angular双向数据绑定原理
angular双向数据绑定原理 从UI到数据:UI事件,ajax请求,timeout等。 从数据到UI:脏检查
学习
- 驼峰法则创建模板
- prefix 是给组件的前缀;
- #heroInput 只能在模板本身作用域内使用,在类内是无法引用的
- 日期管道 date:'yyyy-MM-dd HH:mm:ss'
- ngModule在input上使用时,必须要加入formsModule使用
- JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,如果指定了replacer是一个函数,则可以替换值,或者如果指定了replacer是一个数组,可选的仅包括指定的属性。
7.JSON.parse() 方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的reviver函数用以在返回之前对所得到的对象执行变换(操作)。
- 泛型
T[]表示T类型的数组
function loggingIdentity(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
我们在类那节说过,类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
泛型约束:可以利用接口的方式来进行 number是没有length这个属性的
interface Lengthwise {
length: number;
}
function loggingIdentity(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
loggingIdentity(3); // Error, number doesn't have a .length property
loggingIdentity({length: 10, value: 3});
9.angular的规范:最外层的html必须是class="container"
10.指令和组件的实例有一个生命周期:新建、更新和销毁。 通过实现一个或多个 Angular core 库里定义的生命周期钩子接口,开发者可以介入该生命周期中的这些关键时刻。
10. ngOnChanges 每次@input数据更改的时候调用,
ngOnInit只调用一次
11. ngDoCheck检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。在每个 Angular 脏检查,变更检查 变更检测周期中调用,ngOnChanges() 和 ngOnInit() 之后。
12. ngAfterContentInit 在内容投影进组件以后调用,在第一次ngDoCheck后调用,只调用一次
13. ngAfterContentChecked 内容投射完以后调用,每次ngDoCheck以后都要调用
14. ngAfterViewInit 初始化完组件视图及子视图后调用,第一次ngAfterContentChecked完以后调用,只调用一次
15. ngAfterViewChecked 每次做完组件视图和子视图的变更检测之后调用, ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
16. ngOnDestroy()当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。
在 Angular 销毁指令/组件之前调用。只调用一次
ngDoCheck的特性
- 没发生一次变更检测就会被调用一次
- 谁在负责触发变更?(Zones,它拦截了所有的回调:定时器、事件、ajax)拦截以后去通知angular去做变更检查
- 不要在钩子中写负责的逻辑
js的所有的回调:定时器,事件,ajax
变更检测的两种策略
- default:无论哪个组件发生变化,都会从根组件开始全局遍历调用ngDoCheck()
- OnPush:只有当组件的@Input属性发生变化的时候才会调用本组件的ngDoCheck 就是在@component中添加changeDetection:ChangeDetectionStrategy.OnPush 就可以了。 仔细读这篇文章 https://segmentfault.com/a/1190000010928087
ngAfterViewInit/ ngAfterViewChecked 子组件的先执行,父组件后执行 只有这一对执行了,才算是视图装配完。
- 在组件视图装配的时候调用这两个钩子
- 视图的装配过程中是从子组件向父组件依次进行的。
- 这两个钩子里面不能再修改组件上被绑定的属性( @input进来的属性 ),否则angular会抛异常
- ngAfterViewChecked可能会被调用非常多次,如果没有OnPush策略,所有实现了这个钩子的组件都会被调用,千万不要在这两个钩子里面做复杂的事情,会卡死。到服务器取数据或者大的遍历都不要,最好只是赋值而已。
- 这一对在content那一对的前面先执行,所以在这一对执行的时候,是可以修改组件上被绑定的值的(@input进来的值)
HostListener装饰器跟HostBinding装饰器
- HostListener是关联的方法
- HostBinding是关联的属性
动态组件
-
如何创建动态组件的实例?
-
如何给动态组件传参数?
-
如何监听动态组件的事件?
-
如何销毁动态创建的组件实例?
-
动态创建的类(组件)一定要放到AppModule的entryComponents里面
-
动态创建出来的组件是没办法利用@Input实现传值的
-
子组件如果想要触发事件,就利用@Output的方式
@Output public follow1 = new EventEmitter();
this.follow1.emit("follow");其中字符串follow1是这个方法传出来的值,如果需要方法绑定应该绑定的是(follow1)="sayHello()",如果想在父组件中得到字符串follow,就必须利用sayHello($event)传出值
shadowDoM
- 是一种渲染模式,它的封装性更好,是在当前dom树的基础上,游离出了一个新的dom树,将style跟html都放在单独这个树里面,不会影响到其他的树。
- 使用方式就是在@component中添加encapsulation:ViewEncapsulation.Native,就启动了shadowDom模式。不会引用多于的bootstrap.css样式
- encapsulation:ViewEncapsulation.Emulated实际上是模拟的shadowDom的模式,是模拟的,所以没有真正的shadowDom模式渲染好 这是默认配置,保证当前的样式仅在自身组件使用
内容投影
- 最基本的ng-content用法、 ng-content 这是父组件投影到子组件的内容区域替换,
- 用projection slots投影多块内容
- 把自定义组件投影进去
- 事件的处理方式
contentChild跟ViewChild
- contentChild操作被投影进来的组件 在ngAfterContentInit 里面执行 在这个组件里面可以改变属性跟方法以及赋值这些操作 contentChild用于获取ng-content里面的组件 viewchild就直接获取子组件
模块语法
- 一个组件只能属于一个模块,一个项目必须要有一个根模块app.module.ts
- ./的意思是当前目录下
- service是获取数据的地方,放数据的地方
路由
- path:'**' 通配符,只要输入当前模板没有的,就跳到这里面来
{
path: '',
redirectTo: 'home', //重定向到这里
pathMatch: 'full' //就是空的也会跳转首页
}
Promise
- 创建一个promise对象
模版字符串
1.模板字符串中的数据值变量表示${weather}
APP_INITIALIZER
APP_INITIALIZER 是一个函数,在应用程序初始化时被调用。这就意味着可以通过 AppModule 类的 providers 以 factory 的形式配置它来使用,同时应用程序将会等待它加载完成后进行下一步,所以在这此只适合加载简单的数据。 第一步创建一个provider
待解决区
this.router.events
.pipe(filter(evt => evt instanceof NavigationEnd))
.subscribe(() => this.titleSrv.setTitle());
@HostBinding('class.layout-fixed') get isFixed() { return this.settings.layout.fixed; }
@HostBinding('class.layout-boxed') get isBoxed() { return this.settings.layout.boxed; }
@HostBinding('class.aside-collapsed') get isCollapsed() { return this.settings.layout.collapsed; }
this.message$ = interval(500).pipe(
map(i => this.messages[i]),
take(this.messages.length)
);
interval(500). 这是observal的延时500秒的方法
时刻记住,非纯管道可能每隔几微秒就会被调用一次。 如果你不小心点,这个管道就会发起一大堆请求“攻击”服务器。
Angular 的 AsyncPipe 是一个有趣的非纯管道的例子。 AsyncPipe 接受一个 Promise 或 Observable 作为输入,并且自动订阅这个输入,最终返回它们给出的值。 |async
AsyncPipe 管道是有状态的。 该管道维护着一个所输入的 Observable 的订阅,并且持续从那个 Observable 中发出新到的值。
httpClient()本身就是一个subject数据? this.http.get(url).subscribe( result => this.cachedData = result )
作为发布者,你创建一个 Observable 的实例
Observable.of(...items) —— 返回一个 Observable 实例,它用同步的方式把参数中提供的这些值发送出来。 Observable.from(iterable) —— 把它的参数转换成一个 Observable 实例。 该方法通常用于把一个数组转换成一个(发送多个值的)可观察对象。 next() 函数可以接受消息字符串、事件对象、数字值或各种结构。
使用 Observable 构造函数可以创建任何类型的可观察流。 当执行可观察对象的 subscribe() 方法时,这个构造函数就会把它接收到的参数作为订阅函数来运行。 订阅函数会接收一个 Observer 对象,并把值发布给观察者的 next() 方法。 Rxjs创建observal的三种方式 1.创建可观察对象的函数 (1)formPromise() //承诺 (2) Interval() //定时器 (3)const mouseMoves = fromEvent(el, 'mousemove'); //事件 (4)ajax('api/data') ajax事件 2.操作符 操作符是基于可观察对象构建的一些对集合进行复杂操作的函数 take(count:number) 拿到想要的前count组数据
错误处理
retry(count:number) 在catchError之前调用这个方法,重新调用请求错误的调用数列,如果是http请求,就重新发起那个 HTTP 请求
<ng-container *ngTemplateOutlet="greet"></ng-container>
<hr>
<ng-container *ngTemplateOutlet="eng; context: myContext"></ng-container>
<hr>
<ng-container *ngTemplateOutlet="svk; context: myContext"></ng-container>
<hr>
<ng-template #greet><span>Hello</span></ng-template>
<ng-template #eng let-name><span>Hello {{name}}!</span></ng-template>
<ng-template #svk let-person="localSk"><span>Ahoj {{person}}!</span></ng-template>