0%

angular-misc

Angular杂项

什么操作会触发Angular执行change detection?

这个问题一直没有搞明白,有待进一步研究。
https://angular.io/guide/change-detection
https://www.youtube.com/watch?v=-tB-QDrPmuI

这个问题,现在大概了解了一些,Angular内部使用Zone.js来实现change detection,Zone.js对所有异步操作都进行了monkey patch,当有异步操作发生时,Angular会自动进行更新检测。所以这些动作会出发Angular执行change detection:

  1. setTimeout/setInterval
  2. XMLHttpRequest/fetch
  3. EventListener: click, mouseover, keydown, …
  4. Promise.then
  5. Async/Await

Change detection相关参考资料

  1. https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/ - 尚未阅读。
  2. https://hackernoon.com/everything-you-need-to-know-about-change-detection-in-angular-8006c51d206f - 这个比较老了,用的还是Angular4.0的源码讲解的。
  3. https://stackoverflow.com/questions/42643389/why-do-we-need-ngdocheck/42807309#42807309 - ngDoCheck的作用。

Content

在AOT编译器下,Private变量无法绑定到模板中。

如果在组件中定义了一个私有变量,是不能使用双括弧绑定到模板中的,比如下面的代码:

1
2
3
4
5
6
7
8
@Component({
selector: 'app-order',
templateUrl: './order.component.html',
styleUrls: ['./order.component.less'],
})
export class OrderComponent {
private count = 0;
}
1
<p>{{count}}</p>

这样写是不行的,因为在AOT编译器下,私有变量会被删除,所以无法绑定到模板中,如果想要绑定到模板中,需要将变量定义为公共变量,或者使用get方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
@Component({
selector: 'app-order',
templateUrl: './order.component.html',
styleUrls: ['./order.component.less'],
})
export class OrderComponent {
private _count = 0;

get count(): number {
return this._count;
}
}
1
<p>{{count}}</p>

或者使用getCount()方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
@Component({
selector: 'app-order',
templateUrl: './order.component.html',
styleUrls: ['./order.component.less'],
})
export class OrderComponent {
private count = 0;

private getCount(): number {
return this.count;
}
}
1
<p>{{getCount()}}</p>

AOT vs JIT

Monkey Patching

In computer programming, monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time. It is used to extend or modify the runtime code of dynamic languages such as Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, and Lisp without altering the original source code. - Wikipedia

Angular找不到selector对应的组件时,不会报错。

如果你在Angular template中使用了一个选择器,但是这个选择器没有对应任何组件,那么Angular不会报错,只会将选择器当作一个普通的HTML标签处理。这个问题在开发过程中很容易出现,因为Angular不会报错,所以很难发现。

ng-repeat vs ngFor

  • ng-repeat是AngularJS中的指令,用于循环遍历数组或对象。
  • ngFor是Angular中的指令,用于循环遍历数组或对象。

Angular中的viewProviders和providers

竟然还有viewProvider?真是孤陋寡闻了。

基于配置的换肤方案

因为Angular的模板和样式是在Component元数据中指定的,所以我们可以定义一个变量用来控制模板和样式的变化,从而实现换肤功能。

首先:我们在config目录下新建一个theme.ts文件,用来存放主题相关的配置。这里我们定义一个USE_LIGHT_THEME变量,用来控制是否使用浅色主题。

1
2
// config/theme.ts
export const USE_LIGHT_THEME = true;

然后:我们在app.component.ts中引入USE_LIGHT_THEME变量,根据这个变量的值来选择不同的模板和样式。

1
2
3
4
5
6
7
8
// app.component.ts
import { Component } from '@angular/core';
import { USE_LIGHT_THEME } from './config/theme';

@Component({
selector: 'app-root',
templateUrl: USE_LIGHT_THEME ? './app.component-light.html' : './app.component-dark.html',
styleUrls: USE_LIGHT_THEME ? ['./app.component-light.css'] : ['./app.component-dark.css'],

以上就是一个简单的实现方式,通过更改USE_LIGHT_THEME的值,就可以实现换肤功能。使用这种方法时,我们可以为已有的项目添加换肤功能,而不需要修改原有的代码,只需为每个组件添加一个额外的模板和样式文件即可。(有的甚至只需要添加一个样式文件就行了)。

如何让Angular每五分钟进行一次更新检测?

为什么会有如此奇怪的需求呢,现实中还真有。比如我们使用websocket来实时更新数据,但是websocket的数据更新不会触发Angular的change detection,所以我们需要定时调用ChangeDetectorRef.detectChanges()方法来手动触发更新检测。

这里的做法是首先使用ChangeDetectorRef.detach()方法来暂时关闭自动更新检测,然后使用setInterval()方法每隔5秒调用一次ChangeDetectorRef.detectChanges()方法来手动触发更新检测。

1
2
3
4
5
6
constructor(private ref: ChangeDetectorRef) {
ref.detach();
setInterval(() => {
this.ref.detectChanges();
}, 5000);
}

HostBinding主要用来做什么?

HostBinding装饰器用来绑定宿主元素的属性,比如下面的例子,我们使用HostBinding装饰器将class属性绑定到app-root元素上。

1
2
3
4
5
6
7
8
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@HostBinding('class') class = 'app-root';
}

这样就相当于在app-root元素上添加了一个class="app-root"属性。

MDC

MDC = Material Design Components.

Angular challenges

https://angular-challenges.vercel.app/guides/getting-started/

Angular interview.

https://creators.spotify.com/pod/show/daniel-glejzner/episodes/Angular-Job-Interview---with-GDE-Chau-Tran--Brecht-Billiet-e22mf51/a-a9mqru9

Angular zone.js

  1. https://angular.love/from-zone-js-to-zoneless-angular-and-back-how-it-all-works
  2. https://dev.to/vivekdogra02/angular-zonejs-change-detection-understanding-the-core-concepts-16ek
  3. https://medium.com/@krzysztof.grzybek89/how-runoutsideangular-might-reduce-change-detection-calls-in-your-app-6b4dab6e374d
  4. https://medium.com/@sehban.alam/what-is-zone-js-in-angular-e0029c21c32f
  5. https://www.youtube.com/watch?v=pGBh5oNB2wE

UI framework

  1. PrimeNg - https://primeng.org/
  2. Angular Material - https://material.angular.io/
  3. DevUI - https://devui.design/home

Angular Form

  1. Template-driven form
  2. Reactive form

[(ngModel)] 使用双向绑定必须先导入FormsModule模块。

1
2
3
4
5
6
7
import { FormsModule } from '@angular/forms';

@NgModule({
imports: [
FormsModule
]
})

如何查看Angular编译后的结果?

可以使用ngc命令,详情看这里:https://zdd.github.io/2024/05/21/angular-ngc/

各种Ref

  1. ChangeDetectorRef - 构造函数注入,用于手动触发更新检测。
  2. ElementRef - 构造函数注入,用于获取当前元素的引用, 常用于自定义指令。
  3. ComponentRef - 用于获取组件实例。
  4. ViewContainerRef - 构造函数注入,用于动态创建组件。
  5. TemplateRef - 构造函数注入,用于动态创建组件。
  6. EmbeddedViewRef -
  7. ViewRef

发现一个Angular宝藏

  1. https://angular.love/ - 有空整个通读一下吧,质量非常之高!
  2. https://angular-university.io/ - 这个质量就一般了。