这里有本 Angular 修炼秘籍送你(三)

阅读数:1 2020 年 1 月 7 日 15:37

这里有本Angular修炼秘籍送你(三)

5. 测试用例定义的 [id] 变量,在组件的 ngOnInit() 生命周期钩子拿不到

解决方法:在 ngAfterViewInit() 生命周期钩子可以拿到。
用户写宿主 id 三种方式:
1)给 HTML 属性 id 赋字符串

复制代码
<!-- 赋字符串 -->
<input id='mycheckbox' />
<!-- 赋变量 -->
<input id='{{myId}}'/>

2)给 HTML 属性 id 赋变量

复制代码
<input [attr.id]='mycheckboxid'/>

3)给 DOM 属性 id 赋变量

复制代码
<input [id]='mycheckboxid'/>

组件开发读写宿主 id 的三种方法:
1)读 HTML 属性 id(左右 / 上下滑动可查看全部代码)

复制代码
constructor(@Attribute('id') public hostId ) {}

2)写 HTML 属性 id

复制代码
@HostBinding('attr.id') hostId: string;
DOM 属性 id
@HostBinding('id') hostId: string;

3)读写 DOM 属性 id(左右 / 上下滑动可查看全部代码)

复制代码
constructor(private hostRef: ElementRef ) { }
ngAfterViewInit() {
const id = this.hostRef.nativeElement.id
}

6. 函数作为入参时候,函数尽量写成箭头函数形式

组件开发过程过需要修改或者读取组件属性或者方法时候,一定要写成箭头函数形式,不然会出现 this 指向问题。
比较常见的 2 种应用。
1)定时器:(左右 / 上下滑动可查看全部代码)
let timer = setInterval(() => {
startDist += motion.step * dir;
topy+= motion.step * dir;
if (Math.abs(startDist - startPoint)>= motion.distance) {
clearInterval(timer);
timer = null;
}
}, 1);

2)事件监听:(左右 / 上下滑动可查看全部代码)
document.addEventListener(‘mousemove’, this.mouseMoveHandlerFn);
private mouseMoveHandlerFn = ($event) => {
const option = this.config.options;
}

7. 组件通讯之子获取父的实例

应用场景:组件嵌套,子组件需要用到父组件的属性和方法。
组件嵌套形式如下面代码:
父组件的模板代码如下,父组件嵌套了子组件 app-child。
(左右 / 上下滑动可查看全部代码)

复制代码
<div class="container">
<div *ngFor="let item in items">
<app-child [item]="item"></app-child>
</div>
</div>

方案:在 constructor(构造函数) 中使用 @Inject() 依赖注入父组件。
如下面代码:

复制代码
export class TiBtnItemComponent {
constructor(
@Inject(TiBtnRadioCompontent) private btnRadio: TiBtnRadioCompontent
) {}
}

并且上面的方式是单例的(父组件下不管有几个子组件,父组件只实例化一次),但是这种方式只能注入一个组件实例。
在实际开发中,例如选择按钮组有多选按钮和单选按钮,这个时候就需要注入多个父组件。用上面同样的方式同时注入 2 个就会报如下错误:

原因如下:
当组件申请一个依赖时,Angular 从该组件本身的注入器开始,沿着依赖注入器的树往上找,直到找到第一个符合要求的提供商。如果找不到就会抛出一个错误。

解决方案:
在 @Inject() 装饰前加 @Optional(), 如下面代码:
(左右 / 上下滑动可查看全部代码)

复制代码
export class TiBtnItemComponent {
constructor(
@Optional()@Inject(TiBtnRadioCompontent) private btnRadio: TiBtnRadioCompontent,
@Optional() @Inject(TiBtnCheckboxCompontent) private btnRadio:TiBtnCheckboxCompontent
) {}
}

解决原因:
当 Angular 找不到依赖时,@Optional 装饰器会告诉 Angular 继续执行,Angualr 会把此注入参数设置为 null(而不是默认的抛出错误的行为)。

8. 组件生命周期总结

这里有本Angular修炼秘籍送你(三)

如上图,为组件初始化各个生命周期执行顺序。其中紫色的生命周期只在组件初始化执行一次,绿色的会执行多次。

1)ngOnChanges 频率较低,仅监听用户对 @Input 变量的改变。注意:监听不到组件开发者在代码中对变量更改。可以考虑使用 @Input set 访问器方式,监听变量,所有改变都可以监听到。

2)ngDoCheck,触发频率超高。angular 自身监视 [ngclass] 数组变化,是放在这个生命周期。使用了 IterableDiffers 机制。其他什么情况适合放在这里,暂时不太清楚。

3)ngAfterContentChecked,ngAfterViewChecked 相对频率低。我们目前代码监听 Dom 属性变化,暂时放在这里了。不知道有没有更好办法监听 Dom 属性变化。

注意:如果在 ngAfterViewChecked 里面,改变了模板中使用的变量,此变量不一定能及时更新到试图。需要强制刷新 this.changeDetectorRef.detectChanges();

4)想监听数组和对象属性变化,angular 内部使用了 IterableDiffers 和 KeyValueDiffer。参考 [ngClass] 源码。

本转载自 Think 体验设计公众号。

原文链接: https://mp.weixin.qq.com/s/4bfahysRdH9pVST_UZ4cXg

评论

发布