这个问题是上周的,当时以为这个问题的解决办法太简单了,不用写博客记录,可是潘老师今天今天又遇到了须要使用这个的地方,感受问题虽然不难,可是,写篇博客,方便本身查询,也给了其余人搜索到解决办法的机会。html
项目中使用到了ifame,理想状态是:当点击ifame中的按钮时,将会调用经过angular写的一个函数,函数将会修改一个ngif的判断条件,显示一个弹窗,
但现实是:当点击ifame中的按钮时,将会调用经过angular写的一个函数,函数将会修改一个ngif的判断条件,而后就没有而后了.typescript
开始的时候本身直接懵了, 方法确实执行了, 但界面没修改, 问了问潘老师, 潘老师说看看生命周期函数是否执行了, 果真, 全部的生命周期函数都没有调用。segmentfault
既然生命周期函数没调用,咱们让他调用不就好了,值已经变化了,可是界面不变化,说明,angular 不知道值变化了,因此咱们可让angular 主动进行变动检测,让它知道已经发生了变化。
对此咱们可使用ChangeDetectorRef
promise
Angular 在整个运行期间都会为每个组件建立 ChangeDetectorRef 的实例,该实例提供了相关方法来手动管理变化监测。有了这个类,咱们本身就能够自定义组件的变化监测策略了,如中止/启用变化监测或者按指定路径变化监测等等。
它有如下方法:浏览器
因此,咱们可使用detectChanges()
来达到目标app
// 在组件中注入 constructor(private changeDetectorRef: ChangeDetectorRef) { } // 直接使用 test() { this.changeDetectorRef.detectChanges() }
总结起来, 主要有以下几种状况:异步
setTimeout
,setInterval
Angular并非捕捉对象的变更,它采用的是在适当的时机去检验对象的值是否被改动,这个时机就是这些异步事件的发生。
这个时机是由 Zone.js
去掌控的,它获取到了整个应用的执行上下文,可以对相关的异步事件发生、完成或者异常等进行捕获,而后驱动 Angular 的变化监测机制执行。函数
实际上Zone,js
有一个叫猴子补丁的东西。在Zone.js
运行时,就会为这些异步事件作一层代理包裹,也就是说Zone.js运行后,调用setTimeout、addEventListener
等浏览器异步事件时,再也不是调用原生的方法,而是被猴子补丁包装事后的代理方法。代理里setup了钩子函数, 经过这些钩子函数, 能够方便的进入异步任务执行的上下文.this
//如下是Zone.js启动时执行逻辑的抽象代码片断 function zoneAwareAddEventListener() {...} function zoneAwareRemoveEventListener() {...} function zoneAwarePromise() {...} function patchTimeout() {...} window.prototype.addEventListener=zoneAwareAddEventListener; window.prototype.removeEventListener=zoneAwareRemoveEventListener; window.prototype.promise = zoneAwarePromise; window.prototype.setTimeout = patchTimeout;
关于Zone.js
的详细内容能够看这篇文章。spa
angular 提供了两种变动检测策略,除了上述得Default外还有一种OnPush
的检测机制
OnPush 与 Default 之间的差异: 当检测到与子组件输入绑定的值没有发生改变时,变化检测就不会深刻到子组件中去。
app.comonent.ts
@Component({ selector: 'app-root', template: ` <h1>{{title}}</h1> <h2>user.name: {{user.name}}</h2> <button type="button" (click)="changeUserName()"> 改变属性 </button> <button type="button" (click)="changeUserObject()"> 改变对象 </button> <app-test [user]="user"></app-test> `, }) export class AppComponent { title = 'OnPush Demo'; user: User = new User({name: 'yunzhi'}); changeUserName() { this.user.name = 'new name'; } changeUserObject() { this.user = new User({name: 'new user'}); } }
test.component.ts
@Component({ selector: 'app-test', template: ` <div> <h3>test 组件</h3> <p> <label>User:</label> <span>{{user.name}}</span> </p> </div>`, // 使用OnPush模式只须要加上下面这段代码 changeDetection: ChangeDetectionStrategy.OnPush }) export class TestComponent implements OnInit { @Input() user: User; constructor() { } ngOnInit() { } }
这时当咱们点击改变属性按钮时test组件显示的并不会变化,只有改变user得引用test组件显示的才会变化,以下图所示
原本觉得这个问题没什么可写的,直接解决好像就完事了,但没想到写着写着感受能写的愈来愈多,好比变动检测的顺序
,还有ExpressionChangedAfterItHasBeenCheckedError
都是应该知道的问题
,可是感受这些和主题又没有什么关系,想了想仍是算了。